Compare commits

..
20827 changed files with 142978 additions and 3949149 deletions

No files matched your search

-60
View File
@@ -1,60 +0,0 @@
version: "{branch}.build.{build}"
image: Visual Studio 2019
branches:
except:
- PHP-5.6
- PHP-7.0
clone_depth: 64
skip_commits:
files:
- docs/*
- NEWS
- UPGRADING
- UPGRADING.INTERNALS
cache:
- c:\build-cache
environment:
PHP_BUILD_CACHE_BASE_DIR: c:\build-cache
PHP_BUILD_OBJ_DIR: c:\obj
PHP_BUILD_CACHE_SDK_DIR: c:\build-cache\sdk
PHP_BUILD_SDK_BRANCH: php-sdk-2.2.0
PHP_BUILD_CRT: vs16
# ext and env setup for tests
#MYSQL_TEST_PASSWD: Password12!
#MYSQL_TEST_USER: root
#PDO_MYSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=root password=Password12!"
#PDO_MYSQL_TEST_USER: root
#PDO_MYSQL_TEST_PASS: Password12!
#PGSQL_TEST_CONNSTR: "host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12!"
#PDO_PGSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=Password12!"
#build permutations
matrix:
- THREAD_SAFE: 0
OPCACHE: 0
PARALLEL: -j2
- THREAD_SAFE: 1
OPCACHE: 1
PARALLEL: -j2
INTRINSICS: AVX
services:
# the setup scripts have to be touched, once some other db version is used
- mysql
- postgresql101
- mssql2017
platform:
- x64
# - x86
build_script:
- appveyor\build.bat
test_script:
- appveyor\test.bat
-28
View File
@@ -1,28 +0,0 @@
env:
CIRRUS_CLONE_DEPTH: 1
ARCH: amd64
freebsd_instance:
image_family: freebsd-13-0
task:
name: FREEBSD_DEBUG_NTS
install_script:
#- sed -i -e 's/quarterly/latest/g' /etc/pkg/FreeBSD.conf
#- pkg upgrade -y
- kldload accf_http
- pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp
script:
- ./buildconf -f
- ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d
- gmake -j2
- mkdir /etc/php.d
- gmake install
- echo opcache.enable_cli=1 > /etc/php.d/opcache.ini
- echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
# Specify opcache.preload_user as we're running as root.
- echo opcache.preload_user=root >> /etc/php.d/opcache.ini
tests_script:
- export SKIP_IO_CAPTURE_TESTS=1
- export CI_NO_IPV6=1
- sapi/cli/php run-tests.php -P -q -j2 -g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP --offline --show-diff --show-slow 1000 --set-timeout 120 -d zend_extension=opcache.so
-34
View File
@@ -1,34 +0,0 @@
# https://editorconfig.org/
root = true
[*]
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
charset = utf-8
tab_width = 4
[{*.{awk,bat,c,cpp,d,h,l,re,skl,w32,y},Makefile*}]
indent_size = 4
indent_style = tab
[*.{dtd,html,inc,php,phpt,rng,wsdl,xml,xsd,xsl}]
indent_size = 4
indent_style = space
[*.{ac,m4,sh,yml}]
indent_size = 2
indent_style = space
[*.md]
indent_style = space
max_line_length = 80
[COMMIT_EDITMSG]
indent_size = 4
indent_style = space
max_line_length = 80
[*.patch]
trim_trailing_whitespace = false
-645
View File
@@ -1,645 +0,0 @@
define set_ts
set $tsrm_ls = $arg0
end
document set_ts
set the ts resource, it is impossible for gdb to
call ts_resource_ex while no process is running,
but we could get the resource from the argument
of frame info.
end
define ____executor_globals
if basic_functions_module.zts
set $tsrm_ls = _tsrm_ls_cache
set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1])
set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1])
set $eg_ptr = $eg
else
set $eg = executor_globals
set $cg = compiler_globals
set $eg_ptr = (zend_executor_globals*) &executor_globals
end
end
document ____executor_globals
portable way of accessing executor_globals, set $eg
this also sets compiler_globals to $cg
ZTS detection is automatically based on ext/standard module struct
end
define print_cvs
if $argc == 0
____executor_globals
set $cv_ex_ptr = $eg.current_execute_data
else
set $cv_ex_ptr = (zend_execute_data *)$arg0
end
set $cv_count = $cv_ex_ptr.func.op_array.last_var
set $cv = $cv_ex_ptr.func.op_array.vars
set $cv_idx = 0
set $callFrameSize = (sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval)
printf "Compiled variables count: %d\n\n", $cv_count
while $cv_idx < $cv_count
printf "[%d] '%s'\n", $cv_idx, $cv[$cv_idx].val
set $zvalue = ((zval *) $cv_ex_ptr) + $callFrameSize + $cv_idx
printzv $zvalue
set $cv_idx = $cv_idx + 1
end
end
document print_cvs
Prints the compiled variables and their values.
If a zend_execute_data pointer is set this will print the compiled
variables of that scope. If no parameter is used it will use
current_execute_data for scope.
usage: print_cvs [zend_execute_data *]
end
define dump_bt
set $ex = $arg0
while $ex
printf "[%p] ", $ex
set $func = $ex->func
if $func
if $ex->This->value.obj
if $func->common.scope
printf "%s->", $func->common.scope->name->val
else
printf "%s->", $ex->This->value.obj->ce.name->val
end
else
if $func->common.scope
printf "%s::", $func->common.scope->name->val
end
end
if $func->common.function_name
printf "%s(", $func->common.function_name->val
else
printf "(main"
end
set $callFrameSize = (sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval)
set $count = $ex->This.u2.num_args
set $arg = 0
while $arg < $count
if $arg > 0
printf ", "
end
set $zvalue = (zval *) $ex + $callFrameSize + $arg
set $type = $zvalue->u1.v.type
if $type == 1
printf "NULL"
end
if $type == 2
printf "false"
end
if $type == 3
printf "true"
end
if $type == 4
printf "%ld", $zvalue->value.lval
end
if $type == 5
printf "%f", $zvalue->value.dval
end
if $type == 6
____print_str $zvalue->value.str->val $zvalue->value.str->len
end
if $type == 7
printf "array(%d)[%p]", $zvalue->value.arr->nNumOfElements, $zvalue
end
if $type == 8
printf "object[%p]", $zvalue
end
if $type == 9
printf "resource(#%d)", $zvalue->value.lval
end
if $type == 10
printf "reference"
end
if $type > 10
printf "unknown type %d", $type
end
set $arg = $arg + 1
end
printf ") "
else
printf "??? "
end
if $func != 0
if $func->type == 2
printf "%s:%d ", $func->op_array.filename->val, $ex->opline->lineno
else
printf "[internal function]"
end
end
set $ex = $ex->prev_execute_data
printf "\n"
end
end
document dump_bt
dumps the current execution stack. usage: dump_bt executor_globals.current_execute_data
end
define printzv
set $ind = 1
____printzv $arg0 0
end
document printzv
prints zval contents
end
define ____printzv_contents
set $zvalue = $arg0
set $type = $zvalue->u1.v.type
# 15 == IS_INDIRECT
if $type > 5 && $type < 12
printf "(refcount=%d) ", $zvalue->value.counted->gc.refcount
end
if $type == 0
printf "UNDEF"
end
if $type == 1
printf "NULL"
end
if $type == 2
printf "bool: false"
end
if $type == 3
printf "bool: true"
end
if $type == 4
printf "long: %ld", $zvalue->value.lval
end
if $type == 5
printf "double: %f", $zvalue->value.dval
end
if $type == 6
printf "string: %s", $zvalue->value.str->val
end
if $type == 7
printf "array: "
if ! $arg1
set $ind = $ind + 1
____print_ht $zvalue->value.arr 1
set $ind = $ind - 1
set $i = $ind
while $i > 0
printf " "
set $i = $i - 1
end
end
set $type = 0
end
if $type == 8
printf "object"
____executor_globals
set $handle = $zvalue->value.obj.handle
set $handlers = $zvalue->value.obj.handlers
set $zobj = $zvalue->value.obj
set $cname = $zobj->ce->name->val
printf "(%s) #%d", $cname, $handle
if ! $arg1
if $handlers->get_properties == &zend_std_get_properties
if $zobj->properties
printf "\nProperties "
set $ht = $zobj->properties
set $ind = $ind + 1
____print_ht $ht 1
set $ind = $ind - 1
set $i = $ind
while $i > 0
printf " "
set $i = $i - 1
end
else
printf " {\n"
set $ht = &$zobj->ce->properties_info
set $k = 0
set $num = $ht->nNumUsed
while $k < $num
set $p = (Bucket*)($ht->arData + $k)
set $name = $p->key
set $prop = (zend_property_info*)$p->val.value.ptr
set $val = (zval*)((char*)$zobj + $prop->offset)
printf "%s => ", $name->val
printzv $val
set $k = $k + 1
end
end
end
end
set $type = 0
end
if $type == 9
printf "resource: #%d", $zvalue->value.res->handle
end
if $type == 10
printf "reference: "
____printzv &$zvalue->value.ref->val $arg1
end
if $type == 11
printf "CONSTANT_AST"
end
if $type == 12
printf "indirect: "
____printzv $zvalue->value.zv $arg1
end
if $type == 13
printf "pointer: %p", $zvalue->value.ptr
end
if $type == 15
printf "_ERROR"
end
if $type == 16
printf "_BOOL"
end
if $type == 17
printf "_NUMBER"
end
if $type > 17
printf "unknown type %d", $type
end
printf "\n"
end
define ____printzv
____executor_globals
set $zvalue = $arg0
printf "[%p] ", $zvalue
set $zcontents = (zval*) $zvalue
if $arg1
____printzv_contents $zcontents $arg1
else
____printzv_contents $zcontents 0
end
end
define print_global_vars
____executor_globals
set $symtable = ((HashTable *)&($eg_ptr->symbol_table))
print_ht $symtable
end
document print_global_vars
Prints the global variables
end
define print_const_table
set $ind = 1
printf "[%p] {\n", $arg0
____print_ht $arg0 4
printf "}\n"
end
document print_const_table
Dumps elements of Constants HashTable
Example: print_const_table executor_globals.zend_constants
end
define ____print_ht
set $ht = (HashTable*)$arg0
set $n = $ind
while $n > 0
printf " "
set $n = $n - 1
end
if $ht->u.v.flags & 4
printf "Packed"
else
printf "Hash"
end
printf "(%d)[%p]: {\n", $ht->nNumOfElements, $ht
set $num = $ht->nNumUsed
set $i = 0
set $ind = $ind + 1
while $i < $num
set $p = (Bucket*)($ht->arData + $i)
set $n = $ind
if $p->val.u1.v.type > 0
while $n > 0
printf " "
set $n = $n - 1
end
printf "[%d] ", $i
if $p->key
____print_str $p->key->val $p->key->len
printf " => "
else
printf "%d => ", $p->h
end
if $arg1 == 0
printf "%p\n", (zval *)&$p->val
end
if $arg1 == 1
set $zval = (zval *)&$p->val
____printzv $zval 1
end
if $arg1 == 2
printf "%s\n", (char*)$p->val.value.ptr
end
if $arg1 == 3
set $func = (zend_function*)$p->val.value.ptr
printf "\"%s\"\n", $func->common.function_name->val
end
if $arg1 == 4
set $const = (zend_constant *)$p->val.value.ptr
____printzv $const 1
end
end
set $i = $i + 1
end
set $ind = $ind - 1
printf "}\n"
end
define print_ht
set $ind = 0
____print_ht $arg0 1
end
document print_ht
dumps elements of HashTable made of zval
end
define print_htptr
set $ind = 0
____print_ht $arg0 0
end
document print_htptr
dumps elements of HashTable made of pointers
end
define print_htstr
set $ind = 0
____print_ht $arg0 2
end
document print_htstr
dumps elements of HashTable made of strings
end
define print_ft
set $ind = 0
____print_ht $arg0 3
end
document print_ft
dumps a function table (HashTable)
end
define ____print_inh_class
set $ce = $arg0
if $ce->ce_flags & 0x10 || $ce->ce_flags & 0x20
printf "abstract "
else
if $ce->ce_flags & 0x40
printf "final "
end
end
printf "class %s", $ce->name->val
if $ce->parent != 0
printf " extends %s", $ce->parent->name->val
end
if $ce->num_interfaces != 0
printf " implements"
set $tmp = 0
while $tmp < $ce->num_interfaces
printf " %s", $ce->interfaces[$tmp]->name->val
set $tmp = $tmp + 1
if $tmp < $ce->num_interfaces
printf ","
end
end
end
set $ce = $ce->parent
end
define ____print_inh_iface
set $ce = $arg0
printf "interface %s", $ce->name->val
if $ce->num_interfaces != 0
set $ce = $ce->interfaces[0]
printf " extends %s", $ce->name->val
else
set $ce = 0
end
end
define print_inh
set $ce = $arg0
set $depth = 0
while $ce != 0
set $tmp = $depth
while $tmp != 0
printf " "
set $tmp = $tmp - 1
end
set $depth = $depth + 1
if $ce->ce_flags & 0x80
____print_inh_iface $ce
else
____print_inh_class $ce
end
printf " {\n"
end
while $depth != 0
set $tmp = $depth
while $tmp != 1
printf " "
set $tmp = $tmp - 1
end
printf "}\n"
set $depth = $depth - 1
end
end
define print_pi
set $pi = (zend_property_info *)$arg0
set $initial_offset = ((uint32_t)(zend_uintptr_t)(&((zend_object*)0)->properties_table[(0)]))
set $ptr_to_val = (zval*)((char*)$pi->ce->default_properties_table + $pi->offset - $initial_offset)
printf "[%p] {\n", $pi
printf " offset = %p\n", $pi->offset
printf " ce = [%p] %s\n", $pi->ce, $pi->ce->name->val
printf " flags = 0x%x (", $pi->flags
if $pi->flags & 0x100
printf "ZEND_ACC_PUBLIC"
else
if $pi->flags & 0x200
printf "ZEND_ACC_PROTECTED"
else
if $pi->flags & 0x400
printf "ZEND_ACC_PRIVATE"
else
if $pi->flags & 0x800
printf "ZEND_ACC_EARLY_BINDING"
else
if $pi->flags & 0x20000
printf "ZEND_ACC_SHADOW"
end
end
end
end
end
printf ")\n"
printf " name = "
print_zstr $pi->name
printf " default value: "
printzv $ptr_to_val
printf "}\n"
end
document print_pi
Takes a pointer to an object's property and prints the property information
usage: print_pi <ptr>
end
define ____print_str
set $tmp = 0
set $str = $arg0
if $argc > 2
set $maxlen = $arg2
else
set $maxlen = 256
end
printf "\""
while $tmp < $arg1 && $tmp < $maxlen
if $str[$tmp] > 31 && $str[$tmp] < 127
printf "%c", $str[$tmp]
else
printf "\\%o", $str[$tmp]
end
set $tmp = $tmp + 1
end
if $tmp != $arg1
printf "..."
end
printf "\""
end
define printzn
____executor_globals
set $ind = 0
set $znode = $arg0
if $znode->op_type == 1
set $optype = "IS_CONST"
end
if $znode->op_type == 2
set $optype = "IS_TMP_VAR"
end
if $znode->op_type == 4
set $optype = "IS_VAR"
end
if $znode->op_type == 8
set $optype = "IS_UNUSED"
end
printf "[%p] %s", $znode, $optype
if $znode->op_type == 1
printf ": "
____printzv &$znode->u.constant 0
end
if $znode->op_type == 2
printf ": "
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)
____printzv ((union _temp_variable *)$tvar)->tmp_var 0
end
if $znode->op_type == 4
printf ": "
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)
____printzv *$tvar->var.ptr_ptr 0
end
if $znode->op_type == 8
printf "\n"
end
end
document printzn
print type and content of znode.
usage: printzn &opline->op1
end
define printzops
printf "op1 => "
printzn &execute_data->opline.op1
printf "op2 => "
printzn &execute_data->opline.op2
printf "result => "
printzn &execute_data->opline.result
end
document printzops
dump operands of the current opline
end
define print_zstr
set $zstr = (zend_string *)$arg0
if $argc == 2
set $maxlen = $arg1
else
set $maxlen = $zstr->len
end
printf "string(%d) ", $zstr->len
____print_str $zstr->val $zstr->len $maxlen
printf "\n"
end
document print_zstr
print the length and contents of a zend string
usage: print_zstr <ptr> [max length]
end
define zbacktrace
____executor_globals
dump_bt $eg.current_execute_data
end
document zbacktrace
prints backtrace.
This command is almost a short cut for
> (gdb) ____executor_globals
> (gdb) dump_bt $eg.current_execute_data
end
define lookup_root
set $found = 0
if gc_globals->roots
set $current = gc_globals->roots->next
printf "looking ref %p in roots\n", $arg0
while $current != &gc_globals->roots
if $current->ref == $arg0
set $found = $current
break
end
set $current = $current->next
end
if $found != 0
printf "found root %p\n", $found
else
printf "not found\n"
end
end
end
document lookup_root
lookup a refcounted in root
usage: lookup_root [ptr].
end
-19
View File
@@ -1,19 +0,0 @@
# Replace $Id$ strings with 40-character hexadecimal blob object name.
/ext/ext_skel.php ident
/ext/phar/phar/pharcommand.inc ident
/ext/dba/libinifile/inifile.c ident
/ext/dba/libflatfile/flatfile.c ident
/ext/dba/libcdb/cdb_make.c ident
/ext/dba/libcdb/cdb.c ident
/run-tests.php ident
# A custom merge driver to avoid automatic merges. These are manually merged.
# See https://wiki.php.net/vcs/gitfaq
/NEWS merge=NEWS
/UPGRADING merge=NEWS
/UPGRADING.INTERNALS merge=NEWS
# Enable commit diffs for binary PHP test files. Some PHP test files include
# special characters, such as ASCII control characters. Git recognizes these as
# binary and wouldn't generate diffs.
*.phpt diff
-288
View File
@@ -1,288 +0,0 @@
# These files are generated during building or development and are intentionally
# untracked to ignore by Git. For other development environment specific files,
# such as editor configuration, a good practice is to exclude them using the
# .git/info/exclude in the cloned repository or a global .gitignore file.
# ------------------------------------------------------------------------------
# Common files ignored across the repository
# ------------------------------------------------------------------------------
# Backup copies created by various editors or development tools
*~
# Patches downloaded to patch files or to apply open source contributions
*.patch
# Swap files created by editors and tools to indicate a locked file
*.swp
# Various temporary generated files
*.tmp
# ------------------------------------------------------------------------------
# Generated by the PHP build system
# ------------------------------------------------------------------------------
# Archive library containing .o files, generated during build process
*.a
# Libtool library files generated during build process
*.la
# Directories created by Libtool for storing generated library files
.libs/
# Library object files generated during build process
*.lo
# Temporary library object files generated by compiler and libtool due to failure
*.loT
# Standard object files generated during build process
*.o
# Dependency files generated during build process
*.dep
# Cache directories created by Autoconf tools
autom4te.cache/
# Cache file(s) generated by Autoconf's configure when run as `configure -C`
config.cache
# A log file(s) generated by Autoconf during *nix build system
config.log
# Helper(s) generated by *nix build system to save the last configure command
config.nice
# Generated by Autoconf's configure script for instantiating templates
config.status
# Main *nix build system configuration script(s) generated by Autoconf
configure
# Generated by `./configure` when test programs create temporary files
confdefs.h
conftest*
# Generated by configure scripts on all systems
/main/internal_functions.c
/main/internal_functions_cli.c
# The Libtool script(s) generated by the *nix build system
libtool
# Makefile(s) generated from Makefile fragment templates by `./configure`
Makefile
Makefile.fragments
Makefile.objects
# Directories for shared object files and headers generated by `./configure`
include/
libs/
modules/
# Used by build/gen_stub.php
build/PHP-Parser-*
# ------------------------------------------------------------------------------
# Configuration headers generated by the PHP build system
# ------------------------------------------------------------------------------
config.h
config.h.in
/ext/date/lib/timelib_config.h
/main/build-defs.h
/main/php_config.h.in
/main/php_config.h
/Zend/zend_config.h
# ------------------------------------------------------------------------------
# Manual (man 1 and 8) pages generated from templates for *nix alike systems
# ------------------------------------------------------------------------------
/ext/phar/phar.1
/ext/phar/phar.phar.1
/sapi/cgi/php-cgi.1
/sapi/cli/php.1
/sapi/fpm/php-fpm.1
/sapi/fpm/php-fpm.8
/sapi/phpdbg/phpdbg.1
/scripts/man1/*.1
# ------------------------------------------------------------------------------
# SAPIs specific ignores
# ------------------------------------------------------------------------------
/sapi/apache2handler/libphp.module
/sapi/fpm/fpm/php-cgi
/sapi/fpm/init.d.php-fpm
/sapi/fpm/php-fpm.conf
/sapi/fpm/php-fpm.service
/sapi/fpm/status.html
/sapi/fpm/www.conf
# ------------------------------------------------------------------------------
# Executable binaries and scripts generated during the build process
# ------------------------------------------------------------------------------
/ext/phar/phar.phar
/ext/phar/phar.php
/pear/install-pear-nozlib.phar
/sapi/cgi/php-cgi
/sapi/fpm/php-fpm
/sapi/phpdbg/phpdbg
/scripts/php-config
/scripts/phpize
php
# ------------------------------------------------------------------------------
# Lexer files generated by re2c
# ------------------------------------------------------------------------------
/ext/json/json_scanner.c
/ext/json/php_json_scanner_defs.h
/ext/pdo/pdo_sql_parser.c
/ext/phar/phar_path_check.c
/ext/standard/url_scanner_ex.c
/ext/standard/var_unserializer.c
/sapi/phpdbg/phpdbg_lexer.c
/Zend/zend_ini_scanner.c
/Zend/zend_ini_scanner_defs.h
/Zend/zend_language_scanner.c
/Zend/zend_language_scanner_defs.h
# ------------------------------------------------------------------------------
# PHP parser files generated by bison during the build process
# ------------------------------------------------------------------------------
/ext/json/json_parser.tab.h
/ext/json/json_parser.tab.c
/sapi/phpdbg/phpdbg_parser.c
/sapi/phpdbg/phpdbg_parser.h
/sapi/phpdbg/phpdbg_parser.output
/Zend/zend_ini_parser.c
/Zend/zend_ini_parser.h
/Zend/zend_ini_parser.output
/Zend/zend_language_parser.c
/Zend/zend_language_parser.h
/Zend/zend_language_parser.output
# ------------------------------------------------------------------------------
# Extensions files
# ------------------------------------------------------------------------------
# Miscellaneous extensions files
/ext/opcache/jit/zend_jit_x86.c
/ext/opcache/minilua
# Generated by `cd ext/name && phpize && ./configure`
/ext/*/build/
/ext/*/configure.ac
/ext/*/run-tests.php
# ------------------------------------------------------------------------------
# Generated by Windows build system
# ------------------------------------------------------------------------------
# Generated by `/buildconf.bat`
/configure.bat
/configure.js
# Generated by `/configure.(bat|js)` (architecture dependent)
/config.nice.bat
# NTS debug build x86
/Debug/
# ZTS debug build x86
/Debug_TS/
# NTS build x86
/Release/
# ZTS build x86
/Release_TS/
# Generated by x64 compiler, includes Debug, Debug_TS, Release, Release_TS
/x64/
# Miscellaneous files generated by Windows build system
/main/config.w32.h
/win32/build/deplister.exe
/win32/build/deplister.obj
/win32/*.aps
/win32/*.positions
/win32/*.suo
/win32/ext
/win32/syslog.reg
/win32/wsyslog.h
# Standard object files generated by Visual Studio
*.obj
# ------------------------------------------------------------------------------
# Tests
# ------------------------------------------------------------------------------
# Generated by `./run-tests.php` upon failure
**/tests/**/*.diff
**/tests/**/*.out*
**/tests/**/*.php
**/tests/**/*.exp
**/tests/**/*.log
**/tests/**/*.sh
# Generated by some test cases
**/tests/**/*.db
# Microsoft Access database created for passing to tests
/ext/pdo_odbc/tests/*.mdb
# Files generated by `./run-tests.php -m` when checking for memory leaks
**/tests/**/*.mem
# Test results generated by `./run-tests.php`
php_test_results_*.txt
# Temporary test information generated by `./run-tests.php`
/run-test-info.php
# Temporary POST data placeholder files generated by `./run-tests.php`
phpt.*
# Temporary PHP INI configuration file(s) for tests, generated by `make test`
tmp-php.ini
# ------------------------------------------------------------------------------
# Generated by GCC's gcov and LCOV via build/Makefile.gcov and gcov.php.net
# ------------------------------------------------------------------------------
*.gcda
*.gcno
/gcovr.xml
/gcovr_html/
/lcov_html/
/php_lcov.info
# ------------------------------------------------------------------------------
# Archives generated during the PHP release process
# ------------------------------------------------------------------------------
/*.tar.gz
/*.tar.bz2
/*.tar.xz
/*.tar.gz.asc
/*.tar.bz2.asc
/*.tar.xz.asc
# ------------------------------------------------------------------------------
# Generated by `./configure --enable-dtrace` for using DTrace framework
# ------------------------------------------------------------------------------
/ext/oci8/oci8_dtrace_gen.h
/ext/oci8/oci8_dtrace_gen.h.bak
/Zend/zend_dtrace_gen.h
/Zend/zend_dtrace_gen.h.bak
# ------------------------------------------------------------------------------
# Special cases to invert previous ignore patterns
# ------------------------------------------------------------------------------
!/ext/bcmath/libbcmath/src/config.h
!/ext/fileinfo/libmagic/config.h
!/ext/fileinfo/libmagic.patch
!/ext/fileinfo/magicdata.patch
!/ext/pcre/pcre2lib/config.h
!/win32/build/Makefile
-101
View File
@@ -1,101 +0,0 @@
git:
quiet: true
dist: bionic
language: c
os: linux
addons:
apt:
packages:
- locales
- language-pack-de
- re2c
- ccache
- mysql-server
- libaspell-dev
- libbz2-dev
- libcurl4-gnutls-dev
- libenchant-dev
- libfreetype6-dev
- libgmp-dev
- libicu-dev
- libjpeg-dev
- libkrb5-dev
- libonig-dev
- libpng-dev
- libpq-dev
- libpspell-dev
- libsasl2-dev
- libsqlite3-dev
- libsodium-dev
- libtidy-dev
- libwebp-dev
- libxml2-dev
- libxpm-dev
- libxslt1-dev
- libzip-dev
services:
- mysql
- postgresql
notifications:
email:
on_failure: change
irc:
template:
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} - Change view : %{compare_url} - Build details : %{build_url}"
channels:
- "irc.efnet.org#php.pecl"
on_success: change
on_failure: always
cache:
apt: true
ccache: true
env:
global:
- MYSQL_TEST_HOST=127.0.0.1
- MYSQL_TEST_USER=travis
- PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=test"
- PDO_MYSQL_TEST_USER=travis
- PDO_MYSQL_TEST_PASS=
- PDO_MYSQL_TEST_HOST=127.0.0.1
- PDO_PGSQL_TEST_DSN="pgsql:host=localhost port=5432 dbname=test user=postgres password="
- REPORT_EXIT_STATUS=1
jobs:
include:
- env: ENABLE_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 ARM64=1
arch: arm64-graviton2
dist: bionic
virt: lxd
group: edge
if: type = cron
- env: ENABLE_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 S390X=1
arch: s390x
if: type = cron
before_script:
- ccache --version
- ccache --zero-stats
- export USE_CCACHE=1
# Enable IPv6
- sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'
# Compile PHP
- travis_wait ./travis/compile.sh
# Setup Extensions
- ./travis/setup-mysql.sh
- ./travis/setup-pgsql.sh
# Run PHPs run-tests.php
script:
# ARM64 CI reports nproc=32, which is excessive.
- if [ -z "$ARM64" ]; then export JOBS=$(nproc); else export JOBS=16; fi
- ./sapi/cli/php run-tests.php -P -d extension=`pwd`/modules/zend_test.so $(if [ $ENABLE_DEBUG == 0 ]; then echo "-d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit_buffer_size=16M -d zend_extension=`pwd`/modules/opcache.so"; fi) -g "FAIL,XFAIL,BORK,WARN,LEAK,SKIP" --offline --show-diff --show-slow 1000 --set-timeout 120 -j$JOBS
- sapi/cli/php -d extension_dir=`pwd`/modules -r 'dl("zend_test");'
after_success:
- ccache --show-stats
+149
View File
@@ -0,0 +1,149 @@
PHP Coding Standards
====================
This file lists several standards that any programmer, adding or changing
code in PHP, should follow. Since this file was added at a very late
stage of the development of PHP v3.0, the code base does not (yet) fully
follow it, but it's going in that general direction.
This is an initial version - it'll most probably grow as time passes.
Code Implementation
-------------------
[1] Functions that are given pointers to resources should not free them
For instance, function int mail(char *to, char *from) should NOT free
to and/or from.
Exceptions:
- The function's designated behavior is freeing that resource. E.g. efree()
- The function is given a boolean argument, that controls whether or not
the function may free its arguments (if true - the function must free its
arguments, if false - it must not)
- Low-level parser routines, that are tightly integrated with the token
cache and the bison code for minimum memory copying overhead.
[2] Functions that are tightly integrated with other functions within the
same module, and rely on each other non-trivial behavior, should be
documented as such and declared 'static'. They should be avoided if
possible.
[3] Use definitions and macros whenever possible, so that constants have
meaningful names and can be easily manipulated. The only exceptions
to this rule are 0 and 1, when used as false and true (respectively).
Any other use of a numeric constant to specify different behavior
or actions should be done through a #define.
[4] When writing functions that deal with strings, be sure to remember
that PHP holds the length property of each string, and that it
shouldn't be calculated with strlen(). Write your functions in a such
a way so that they'll take advantage of the length property, both
for efficiency and in order for them to be binary-safe.
Functions that change strings and obtain their new lengths while
doing so, should return that new length, so it doesn't have to be
recalculated with strlen() (e.g. _php3_addslashes())
[5] Use php3_error() to report any errors/warnings during code execution.
Use descriptive error messages, and try to avoid using identical
error strings for different stages of an error. For example,
if in order to obtain a URL you have to parse the URL, connect,
and retreive the text, assuming something can go wrong at each
of these stages, don't report an error "Unable to get URL"
on all of them, but instead, write something like "Unable
to parse URL", "Unable to connect to URL server" and "Unable
to fetch URL text", respectively.
[6] NEVER USE strncat(). If you're absolutely sure you know what you're doing,
check its man page again, and only then, consider using it, and even then,
try avoiding it.
Naming Conventions
------------------
[1] Function names for user functions implementation should be prefixed with
"php3_", and followed by a word or an underscore-delimited list of words,
in lowercase letters, that describes the function.
[2] Function names used by user functions implementations should be prefixed
with "_php3_", and followed by a word or an underscore-delimited list of
words, in lowercase letters, that describes the function. If applicable,
they should be declared 'static'.
[3] Variable names must be meaningful. One letter variable names must be
avoided, except for places where the variable has no real meaning or
a trivial meaning (e.g. for (i=0; i<100; i++) ...).
[4] Variable names should be in lowercase; Use underscores to seperate
between words.
Syntax and indentation
----------------------
[1] Never use C++ style comments (i.e. // comment). Always use C-style
comments instead. PHP is written in C, and is aimed at compiling
under any ANSI-C compliant compiler. Even though many compilers
accept C++-style comments in C code, you have to ensure that your
code would compile with other compilers as well.
The only exception to this rule is code that is Win32-specific,
because the Win32 port is MS-Visual C++ specific, and this compiler
is known to accept C++-style comments in C code.
[2] Use K&R-style. Of course, we can't and don't want to
force anybody to use a style she's not used to, but
at the very least, when you write code that goes into the core
of PHP or one of its standard modules, please maintain the K&R
style. This applies to just about everything, starting with
indentation and comment styles and up to function decleration
syntax.
[3] Be generous with whitespace and braces. Always prefer
if (foo) {
bar;
}
to
if(foo)bar;
Keep one empty line between the variable decleration section and
the statements in a block, as well as between logical statement
groups in a block. Maintain at least one empty line between
two functions, preferably two.
Documentation and Folding Hooks
-------------------------------
In order to make sure that the online documentation stays in line with
the code, each user-level function should have its user-level function
prototype before it along with a brief one-line description of what the
function does. It would look like this:
/* {{{ proto int abs(int number)
Return the absolute value of the number */
void php3_abs(INTERNAL_FUNCTION_PARAMETERS) {
...
}
/* }}} */
The {{{ symbols are the default folding symbols for the folding mode in
Emacs. vim will soon have support for folding as well. Folding is very
useful when dealing with large files because you can scroll through the
file quickly and just unfold the function you wish to work on. The }}}
at the end of each function marks the end of the fold, and should be on
a separate line.
The "proto" keyword there is just a helper for the doc/genfuncsummary script
which generates a full function summary. Having this keyword in front of the
function prototypes allows us to put folds elsewhere in the code without
messing up the function summary.
Optional arguments are written like this:
/* {{{ proto object imap_header(int stream_id, int msg_no [, int from_length [, int subject_length [, string default_host]]])
And yes, please keep everything on a single line, even if that line is massive.
-320
View File
@@ -1,320 +0,0 @@
# PHP coding standards
This file lists several standards that any programmer adding or changing code in
PHP should follow. Since this file was added at a very late stage of the
development of PHP v3.0, the code base does not fully follow it, but new
features are going in that general direction. Many sections have been rewritten to
use these rules.
## Code implementation
1. Document your code in source files and the manual. (tm)
2. Functions that are given pointers to resources should not free them.
For instance, `function int mail(char *to, char *from)` should NOT free to
and/or from.
Exceptions:
* The function's designated behavior is freeing that resource. E.g.
`efree()`
* The function is given a boolean argument, that controls whether or not the
function may free its arguments (if true - the function must free its
arguments, if false - it must not)
* Low-level parser routines, that are tightly integrated with the token
cache and the bison code for minimum memory copying overhead.
3. Functions that are tightly integrated with other functions within the same
module, and rely on each other non-trivial behavior, should be documented as
such and declared `static`. They should be avoided if possible.
4. Use definitions and macros whenever possible, so that constants have
meaningful names and can be easily manipulated. The only exceptions to this
rule are 0 and 1, when used as `false` and `true` (respectively). Any other
use of a numeric constant to specify different behavior or actions should be
done through a `#define`.
5. When writing functions that deal with strings, be sure to remember that PHP
holds the length property of each string, and that it shouldn't be
calculated with `strlen()`. Write your functions in such a way so that
they'll take advantage of the length property, both for efficiency and in
order for them to be binary-safe. Functions that change strings and obtain
their new lengths while doing so, should return that new length, so it
doesn't have to be recalculated with `strlen()` (e.g. `php_addslashes()`).
6. NEVER USE `strncat()`. If you're absolutely sure you know what you're doing,
check its man page again, and only then, consider using it, and even then,
try avoiding it.
7. Use `PHP_*` macros in the PHP source, and `ZEND_*` macros in the Zend part of
the source. Although the `PHP_*` macros are mostly aliased to the `ZEND_*`
macros it gives a better understanding on what kind of macro you're calling.
8. When commenting out code using a `#if` statement, do NOT use `0` only.
Instead use `"<git username here>_0"`. For example, `#if FOO_0`, where `FOO`
is your git user `foo`. This allows easier tracking of why code was
commented out, especially in bundled libraries.
9. Do not define functions that are not available. For instance, if a library is
missing a function, do not define the PHP version of the function, and do
not raise a run-time error about the function not existing. End users should
use `function_exists()` to test for the existence of a function.
10. Prefer `emalloc()`, `efree()`, `estrdup()`, etc. to their standard C library
counterparts. These functions implement an internal "safety-net" mechanism
that ensures the deallocation of any unfreed memory at the end of a request.
They also provide useful allocation and overflow information while running
in debug mode.
In almost all cases, memory returned to the engine must be allocated using
`emalloc()`.
The use of `malloc()` should be limited to cases where a third-party library
may need to control or free the memory, or when the memory in question needs
to survive between multiple requests.
## User functions/methods naming conventions
1. Function names for user-level functions should be enclosed with in the
`PHP_FUNCTION()` macro. They should be in lowercase, with words underscore
delimited, with care taken to minimize the letter count. Abbreviations
should not be used when they greatly decrease the readability of the
function name itself:
Good:
```php
str_word_count
array_key_exists
```
Ok:
```php
date_interval_create_from_date_string
// Could be 'date_intvl_create_from_date_str'?
get_html_translation_table()
// Could be 'html_get_trans_table'?
```
Bad:
```php
hw_GetObjectByQueryCollObj
pg_setclientencoding
jf_n_s_i
```
2. If they are part of a "parent set" of functions, that parent should be
included in the user function name, and should be clearly related to the
parent program or function family. This should be in the form of `parent_*`:
A family of `foo` functions, for example:
Good:
```php
foo_select_bar
foo_insert_baz
foo_delete_baz
```
Bad:
```php
fooselect_bar
fooinsertbaz
delete_foo_baz
```
3. Function names used by user functions should be prefixed with `_php_`, and
followed by a word or an underscore-delimited list of words, in lowercase
letters, that describes the function. If applicable, they should be declared
`static`.
4. Variable names must be meaningful. One letter variable names must be avoided,
except for places where the variable has no real meaning or a trivial
meaning (e.g. `for (i=0; i<100; i++) ...`).
5. Variable names should be in lowercase. Use underscores to separate between
words.
6. Method names follow the *studlyCaps* (also referred to as *bumpy case* or
*camel caps*) naming convention, with care taken to minimize the letter
count. The initial letter of the name is lowercase, and each letter that
starts a new `word` is capitalized:
Good:
```php
connect()
getData()
buildSomeWidget()
```
Bad:
```php
get_Data()
buildsomewidget()
getI()
```
7. Class names should be descriptive nouns in *PascalCase* and as short as
possible. Each word in the class name should start with a capital letter,
without underscore delimiters. The class name should be prefixed with the
name of the "parent set" (e.g. the name of the extension) if no namespaces
are used. Abbreviations and acronyms as well as initialisms should be
avoided wherever possible, unless they are much more widely used than the
long form (e.g. HTTP or URL). Abbreviations start with a capital letter
followed by lowercase letters, whereas acronyms and initialisms are written
according to their standard notation. Usage of acronyms and initialisms is
not allowed if they are not widely adopted and recognized as such.
Good:
```php
Curl
CurlResponse
HTTPStatusCode
URL
BTreeMap // B-tree Map
Id // Identifier
ID // Identity Document
Char // Character
Intl // Internationalization
Radar // Radio Detecting and Ranging
```
Bad:
```php
curl
curl_response
HttpStatusCode
Url
BtreeMap
ID // Identifier
CHAR
INTL
RADAR // Radio Detecting and Ranging
```
## Internal function naming conventions
1. Functions that are part of the external API should be named
`php_modulename_function()` to avoid symbol collision. They should be in
lowercase, with words underscore delimited. Exposed API must be defined in
`php_modulename.h`.
```c
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS);
```
Unexposed module function should be static and should not be defined in
`php_modulename.h`.
```c
static int php_session_destroy()
```
2. Main module source file must be named `modulename.c`.
3. Header file that is used by other sources must be named `php_modulename.h`.
## Syntax and indentation
1. Never use C++ style comments (i.e. `//` comment). Always use C-style comments
instead. PHP is written in C, and is aimed at compiling under any ANSI-C
compliant compiler. Even though many compilers accept C++-style comments in
C code, you have to ensure that your code would compile with other compilers
as well. The only exception to this rule is code that is Win32-specific,
because the Win32 port is MS-Visual C++ specific, and this compiler is known
to accept C++-style comments in C code.
2. Use K&R-style. Of course, we can't and don't want to force anybody to use a
style he or she is not used to, but, at the very least, when you write code
that goes into the core of PHP or one of its standard modules, please
maintain the K&R style. This applies to just about everything, starting with
indentation and comment styles and up to function declaration syntax. Also
see [Indentstyle](http://www.catb.org/~esr/jargon/html/I/indent-style.html).
3. Be generous with whitespace and braces. Keep one empty line between the
variable declaration section and the statements in a block, as well as
between logical statement groups in a block. Maintain at least one empty
line between two functions, preferably two. Always prefer:
```c
if (foo) {
bar;
}
```
to:
```c
if(foo)bar;
```
4. When indenting, use the tab character. A tab is expected to represent four
spaces. It is important to maintain consistency in indenture so that
definitions, comments, and control structures line up correctly.
5. Preprocessor statements (`#if` and such) MUST start at column one. To indent
preprocessor directives you should put the `#` at the beginning of a line,
followed by any number of whitespace.
## Testing
1. Extensions should be well tested using `*.phpt` tests. Read about that at
[qa.php.net](https://qa.php.net/write-test.php) documentation.
## Folding hooks
Use `{{{` symbols for the folding mode in Emacs and vim (`set fdm=marker`).
Folding is very useful when dealing with large files because you can scroll
through the file quickly and just unfold the function you wish to work on.
The `}}}` at the end of each function marks the end of the fold, and should
be on a separate line.
```c
/* {{{ Returns the absolute value of the number */
PHP_FUNCTION(abs)
{
...
}
/* }}} */
```
## New and experimental functions
To reduce the problems normally associated with the first public implementation
of a new set of functions, it has been suggested that the first implementation
include a file labeled `EXPERIMENTAL` in the function directory, and that the
functions follow the standard prefixing conventions during their initial
implementation.
The file labelled `EXPERIMENTAL` should include the following information:
* Any authoring information (known bugs, future directions of the module).
* Ongoing status notes which may not be appropriate for Git comments.
In general new features should go to PECL or experimental branches until there
are specific reasons for directly adding it to the core distribution.
## Aliases & legacy documentation
You may also have some deprecated aliases with close to duplicate names, for
example, `somedb_select_result` and `somedb_selectresult`. For documentation
purposes, these will only be documented by the most current name, with the
aliases listed in the documentation for the parent function. For ease of
reference, user-functions with completely different names, that alias to the
same function (such as `highlight_file` and `show_source`), will be separately
documented.
Backwards compatible functions and names should be maintained as long as the
code can be reasonably be kept as part of the codebase. See the `README` in the
PHP documentation repository for more information on documentation.
-425
View File
@@ -1,425 +0,0 @@
# Contributing to PHP
Anybody who programs in PHP can be a contributing member of the community that
develops and deploys it; the task of deploying PHP, documentation and associated
websites is a never ending one. With every release, or release candidate comes a
wave of work, which takes a lot of organization and co-ordination.
You don't need any special access to download, build, debug and begin submitting
PHP or PECL code, tests or documentation. Once you've followed this guide and
had several contributions accepted, commit privileges are often quickly granted.
## Index
* [Pull requests](#pull-requests)
* [Filing bugs](#filing-bugs)
* [Feature requests](#feature-requests)
* [Writing tests](#writing-tests)
* [Writing documentation](#writing-documentation)
* [Getting help](#getting-help)
* [PHP source code directory structure](#php-source-code-directory-structure)
* [PHP internals](#php-internals)
* [PECL extensions](#pecl-extensions)
* [Checklist for submitting contribution](#checklist-for-submitting-contribution)
* [What happens after submitting contribution?](#what-happens-after-submitting-contribution)
* [What happens when your contribution is applied?](#what-happens-when-your-contribution-is-applied)
* [Git commit rules](#git-commit-rules)
* [Copyright and license headers](#copyright-and-license-headers)
## Pull requests
PHP welcomes pull requests to [add tests](#writing-tests), fix bugs and to
implement RFCs. Please be sure to include tests as appropriate!
If you are fixing a bug, then please submit your PR against the lowest actively
supported branch of PHP that the bug affects (only green branches on
[the supported version page](https://www.php.net/supported-versions.php) are
supported). For example, at the time of writing, the lowest supported version is
PHP 7.3, which corresponds to the `PHP-7.3` branch in Git. Please also make sure
you add a link to the PR in the bug on [the bug tracker](https://bugs.php.net/).
Pull requests implementing RFCs should be submitted against `master`.
Pull requests should *never* be submitted against `PHP-x.y.z` branches, as these
are only used for release management.
If your pull request exhibits conflicts with the base branch, please resolve
them by using `git rebase` instead of `git merge`.
Fork the official PHP repository and send a pull request. A notification will be
sent to the pull request mailing list. Sending a note to PHP Internals list
(internals@lists.php.net) may help getting more feedback and quicker turnaround.
You can also add pull requests to [bug reports](https://bugs.php.net/).
Read [Git access page](https://www.php.net/git.php) for help on using Git to get
and build PHP source code. We recommend to look at our
[workflow](https://wiki.php.net/vcs/gitworkflow) and our
[FAQ](https://wiki.php.net/vcs/gitfaq).
## Filing bugs
Bugs can be filed on the [PHP bug tracker](https://bugs.php.net/). If this is
the first time you've filed a bug, we suggest reading the
[guide to reporting a bug](https://bugs.php.net/how-to-report.php).
Where possible, please include a self-contained reproduction case!
## Feature requests
Feature requests are generally submitted in the form of
[Requests for Comments (RFC)](https://wiki.php.net/rfc/howto), ideally
accompanied by [pull requests](#pull-requests). You can find the extremely large
list of RFCs that have been previously considered on the
[PHP Wiki](https://wiki.php.net/rfc).
To create a RFC, discuss it with the extension maintainer, and discuss it on the
development mailing list internals@lists.php.net. RFC Wiki accounts can be
requested on https://wiki.php.net/start?do=register. PHP extension maintainers
can be found in the [EXTENSIONS](/EXTENSIONS) file in the PHP source code
repository. Mailing list subscription is explained on the
[mailing lists page](https://www.php.net/mailing-lists.php).
You may also want to read
[The Mysterious PHP RFC Process](https://blogs.oracle.com/opal/entry/the_mysterious_php_rfc_process)
for additional notes on the best way to approach submitting an RFC.
## Writing tests
We love getting new tests! PHP is a huge project and improving code coverage is
a huge win for every PHP user.
[Our QA site includes a page detailing how to write test cases.](https://qa.php.net/write-test.php)
Submitting test scripts helps us to understand what functionality has changed.
It is important for the stability and maintainability of PHP that tests are
comprehensive.
Failure conditions of `zend_parse_parameters`, `ZEND_PARSE_PARAMETERS()` and
similar functions should not be tested. These parameter parsing APIs are already
extensively tested, and additional tests only complicate future modifications.
For newly created tests, a `--CREDITS--` section should no longer be included,
as test authorship is already accurately tracked by Git. If multiple authors
should be credited, the `Co-authored-by` tag in the commit message may be used.
## Writing documentation
There are two ways to contribute to the PHP manual. You can edit the manual and
send patches anonymously via [the online editor](https://edit.php.net/), or you
can check the XML source out from Subversion and edit that and build it
[per the instructions on the documentation site](http://doc.php.net/tutorial/).
Patches created that way should be sent to the
[documentation mailing list](mailto:phpdoc@lists.php.net).
## Getting help
If you are having trouble contributing to PHP, or just want to talk to a human
about what you're working on, you can contact us via the
[internals mailing list](mailto:internals@lists.php.net), or the
[documentation mailing list](mailto:phpdoc@lists.php.net) for documentation
issues.
Although not a formal channel, you can also find a number of core developers on
the #php.pecl channel on [EFnet](http://www.efnet.org/). Similarly, many
documentation writers can be found on #php.doc. Windows development IRC channel
is available at #winphp-dev on FreeNode.
## PHP source code directory structure
PHP source code also includes several files generated during development and
several parts where maintenance is happening upstream in their respective
locations.
```bash
<php-src>/
├─ .git/ # Git configuration and source directory
├─ TSRM/ # Thread Safe Resource Manager
└─ Zend/ # Zend Engine
├─ asm/ # Bundled from src/asm in https://github.com/boostorg/context
├─ zend_vm_execute.h # Generated by `Zend/zend_vm_gen.php`
├─ zend_vm_opcodes.c # Generated by `Zend/zend_vm_gen.php`
├─ zend_vm_opcodes.h # Generated by `Zend/zend_vm_gen.php`
└─ ...
├─ appveyor/ # Appveyor CI service files
└─ build/ # *nix build system files
├─ ax_*.m4 # https://github.com/autoconf-archive/autoconf-archive
├─ config.guess # https://git.savannah.gnu.org/cgit/config.git
├─ config.sub # https://git.savannah.gnu.org/cgit/config.git
├─ libtool.m4 # https://git.savannah.gnu.org/cgit/libtool.git
├─ ltmain.sh # https://git.savannah.gnu.org/cgit/libtool.git
├─ pkg.m4 # https://gitlab.freedesktop.org/pkg-config/pkg-config
├─ shtool # https://www.gnu.org/software/shtool/
└─ ...
├─ docs/ # PHP internals and repository documentation
└─ ext/ # PHP core extensions
└─ bcmath/
├─ libbcmath/ # Forked and maintained in php-src
└─ ...
└─ curl/
├─ sync-constants.php # The curl symbols checker
└─ ...
└─ date/
└─ lib/ # Bundled datetime library https://github.com/derickr/timelib
├─ parse_date.c # Generated by re2c 0.15.3
├─ parse_iso_intervals.c # Generated by re2c 0.15.3
└─ ...
└─ ...
└─ ffi/
├─ ffi_parser.c # Generated by https://github.com/dstogov/llk
└─ ...
└─ fileinfo/
├─ libmagic/ # Modified libmagic https://github.com/file/file
├─ data_file.c # Generated by `ext/fileinfo/create_data_file.php`
├─ libmagic.patch # Modifications patch from upstream libmagic
├─ magicdata.patch # Modifications patch from upstream libmagic
└─ ...
└─ gd/
├─ libgd/ # Bundled and modified GD library https://github.com/libgd/libgd
└─ ...
└─ mbstring/
├─ libmbfl/ # Forked and maintained in php-src
├─ unicode_data.h # Generated by `ext/mbstring/ucgendat/ucgendat.php`
└─ ...
└─ pcre/
├─ pcre2lib/ # https://www.pcre.org/
└─ ...
└─ pdo_mysql/
├─ php_pdo_mysql_sqlstate.h # Generated by `ext/pdo_mysql/get_error_codes.php`
└─ ...
└─ skeleton/ # Skeleton for developing new extensions with `ext/ext_skel.php`
└─ ...
└─ standard/
└─ html_tables/
├─ mappings/ # https://www.unicode.org/Public/MAPPINGS/
└─ ...
├─ credits_ext.h # Generated by `scripts/dev/credits`
├─ credits_sapi.h # Generated by `scripts/dev/credits`
├─ html_tables.h # Generated by `ext/standard/html_tables/html_table_gen.php`
└─ ...
└─ tokenizer/
├─ tokenizer_data.c # Generated by `ext/tokenizer/tokenizer_data_gen.sh`
└─ ...
└─ zend_test # For testing internal APIs. Not needed for regular builds.
└─ ...
└─ zip/ # Bundled https://github.com/pierrejoye/php_zip
└─ ...
└─ ...
└─ main/ # Binding that ties extensions, SAPIs, and engine together
├─ streams/ # Streams layer subsystem
├─ php_version.h # Generated by release managers using `configure`
└─ ...
├─ pear/ # PEAR installation
└─ sapi/ # PHP SAPI modules
└─ cli/
├─ mime_type_map.h # Generated by `sapi/cli/generate_mime_type_map.php`
└─ ...
└─ ...
├─ scripts/ # php-config, phpize and internal development scripts
├─ tests/ # Core features tests
├─ travis/ # Travis CI service files
└─ win32/ # Windows build system files
├─ cp_enc_map.c # Generated by `win32/cp_enc_map_gen.exe`
└─ ...
└─ ...
```
## PHP internals
For information on PHP internal C functions see
[References about Maintaining and Extending PHP](https://wiki.php.net/internals/references).
Various external resources can be found on the web. A standard printed reference
is the book "Extending and Embedding PHP" by Sara Golemon.
## PECL extensions
If you are fixing broken functionality in a [PECL](https://pecl.php.net)
extension then create a bug or identify an existing bug at
[bugs.php.net](https://bugs.php.net). A bug can be used to track the change
progress and prevent your changes getting lost in the PHP mail archives. Some
PECL extensions have their own bug tracker locations and different contributing
procedures.
If your change is large then create a
[Request for Comments (RFC)](https://wiki.php.net/rfc), discuss it with the
extension maintainer, and discuss it on the development mailing list
pecl-dev@lists.php.net depending on the extension. PECL mailing list
subscription is explained on the
[PECL support page](https://pecl.php.net/support.php).
Update any open bugs and add a link to the source of your change. Send the patch
or pointer to the bug to pecl-dev@lists.php.net. Also CC the extension
maintainer. Explain what has been changed by your patch. Test scripts should be
included.
## Checklist for submitting contribution
- Read [Coding standards](/CODING_STANDARDS.md) before you start working.
- Update git source just before running your final `diff` and before testing.
- Add in-line comments and/or have external documentation ready. Use only
`/* */` style comments, not `//`.
- Create test scripts for use with `make test`.
- Run `make test` to check your change doesn't break other features.
- Rebuild PHP with `--enable-debug` which will show some kinds of memory errors
and check the PHP and web server error logs after running your PHP tests.
- Rebuild PHP with `--enable-zts` to check your change compiles and operates
correctly in a thread safe PHP.
- Review the change once more just before submitting it.
## What happens after submitting contribution?
If your change is easy to review and obviously has no side-effects, it might be
committed relatively quickly.
Because PHP is a volunteer-driven effort more complex changes will require
patience on your side. If you do not receive feedback in a few days, consider
bumping. Before doing this think about these questions:
- Did I send the patch to the right mailing list?
- Did I review the mailing list archives to see if these kind of changes had
been discussed before?
- Did I explain my change clearly?
- Is my change too hard to review? Because of what factors?
## What happens when your contribution is applied?
Your name will likely be included in the Git commit log. If your change affects
end users, a brief description and your name might be added to the [NEWS](/NEWS)
file.
## Git commit rules
This section refers to contributors that have Git push access and make commit
changes themselves. We'll assume you're basically familiar with Git, but feel
free to post your questions on the mailing list. Please have a look at the more
detailed [information on Git](https://git-scm.com/).
PHP is developed through the efforts of a large number of people. Collaboration
is a Good Thing(tm), and Git lets us do this. Thus, following some basic rules
with regards to Git usage will:
* Make everybody happier, especially those responsible for maintaining PHP
itself.
* Keep the changes consistently well documented and easily trackable.
* Prevent some of those 'Oops' moments.
* Increase the general level of good will on planet Earth.
Having said that, here are the organizational rules:
1. Respect other people working on the project.
2. Discuss any significant changes on the list before committing and get
confirmation from the release manager for the given branch.
3. Look at [EXTENSIONS](/EXTENSIONS) file to see who is the primary maintainer
of the code you want to contribute to.
4. If you "strongly disagree" about something another person did, don't start
fighting publicly - take it up in private email.
5. If you don't know how to do something, ask first!
6. Test your changes before committing them. We mean it. Really. To do so use
`make test`.
7. For development use the `--enable-debug` switch to avoid memory leaks and the
`--enable-zts` switch to ensure your code handles TSRM correctly and doesn't
break for those who need that.
Currently we have the following branches in use:
| Branch | |
| --------- | --------- |
| master | Active development branch for PHP 8.1, which is open for backwards incompatible changes and major internal API changes. |
| PHP-8.0 | Is used to release the PHP 8.0.x series. This is a current stable version and is open for bugfixes only. |
| PHP-7.4 | Is used to release the PHP 7.4.x series. This is a current stable version and is open for bugfixes only. |
| PHP-7.3 | Is used to release the PHP 7.3.x series. This is a current stable version and is open for bugfixes only. |
| PHP-7.2 | Is used to release the PHP 7.2.x series. This is an old stable version and is open for security fixes only. |
| PHP-7.1 | This branch is closed. |
| PHP-7.0 | This branch is closed. |
| PHP-5.6 | This branch is closed. |
| PHP-5.5 | This branch is closed. |
| PHP-5.4 | This branch is closed. |
| PHP-5.3 | This branch is closed. |
| PHP-5.2 | This branch is closed. |
| PHP-5.1 | This branch is closed. |
| PHP-4.4 | This branch is closed. |
| PHP-X.Y.Z | These branches are used for the release managers for tagging the releases, hence they are closed to the general public. |
The next few rules are more of a technical nature:
1. All non-security bugfix changes should first go to the lowest bugfix branch
(i.e. 7.3) and then get merged up to all other branches. All security fixes
should go to the lowest security fixes branch (i.e 7.2). If a change is not
needed for later branches (i.e. fixes for features which were dropped from
later branches) an empty merge should be done.
2. All news updates intended for public viewing, such as new features, bug
fixes, improvements, etc., should go into the NEWS file of *any stable
release* version with the given change. In other words, news about a bug fix
which went into PHP-5.4, PHP-5.5 and master should be noted in both
PHP-5.4/NEWS and PHP-5.5/NEWS but not master, which is not a public released
version yet.
3. Do not commit multiple files and dump all messages in one commit. If you
modified several unrelated files, commit each group separately and provide a
nice commit message for each one. See example below.
4. Do write your commit message in such a way that it makes sense even without
the corresponding diff. One should be able to look at it, and immediately
know what was modified. Definitely include the function name in the message
as shown below.
5. In your commit messages, keep each line shorter than 80 characters. And try
to align your lines vertically, if they wrap. It looks bad otherwise.
6. If you modified a function that is callable from PHP, prepend PHP to the
function name as shown below.
The format of the commit messages is pretty simple.
<max 79 characters short description>\n
\n
<long description, 79 chars per line>
\n
An Example from the git project (commit 2b34e486bc):
pack-objects: Fix compilation with NO_PTHREDS
It looks like commit 99fb6e04 (pack-objects: convert to use parse_options(),
2012-02-01) moved the #ifdef NO_PTHREDS around but hasn't noticed that the
'arg' variable no longer is available.
If you fix some bugs, you should note the bug ID numbers in your commit message.
Bug ID should be prefixed by `#`.
Example:
Fixed bug #14016 (pgsql notice handler double free crash bug.)
When you change the NEWS file for a bug fix, then please keep the bugs sorted in
decreasing order under the fixed version.
## Copyright and license headers
New source code files should include the following header block:
```c
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: |
+----------------------------------------------------------------------+
*/
```
Thank you for contributing to PHP!
+3
View File
@@ -0,0 +1,3 @@
For the list of people who've put work into PHP 4.0, please see
http://www.php.net/version4/credits.php
+217
View File
@@ -0,0 +1,217 @@
PHP 4.0 CHANGE LOG ChangeLog
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ?? 1999, Version 4.0 Beta 3
- Added '--disable-rpath' option (Sascha)
- Added AOLserver SAPI module (Sascha)
- Fixed XML Callbacks. (Thies)
- Updated ODBC to use the new high-performance Zend function API (kara)
- Updated zlib to use the new high-performance Zend function API. (Stefan)
- Updated preg_split() to allow returning only non-empty pieces (Andrei)
- Updated PCRE to use the new high-performance Zend function API (Andrei)
- Updated session, dba, mhash, mcrypt, sysvshm, sysvsem, gettext modules to use
the new high-performance Zend function API (Sascha)
- Extended var_dump to handle resource type somewhat (Andrei)
- Updated WDDX to use the new high-performance Zend function API (Andrei)
- Updated XML to use the new high-performance Zend function API. (Thies)
- Updated Oracle to use the new high-performance Zend function API. (Thies)
- Improved the performance of the MySQL module significantly by using the new
high-performance Zend function API. (Zeev)
- Add support for the Easysoft ODBC-ODCB Bridge (martin@easysoft.com)
- Fix bug in odbc_setoption, getParameter call incorrect (martin@easysoft.com)
- Ora_Fetch_Into now resets the returned array in all cases (Thies)
- Fixed NULL-Column problem in Oracle-Driver (Thies)
- Added extra metadata functions to ODBC, SQLTables etc (nick@easysoft.com)
- Fixed SEGV in mcal make_event_object() and
typo in mcal_list_alarms() (Andrew Skalski)
- Fixed Ora_PLogon (Thies)
- Resourcified Oracle (Thies)
- Implemented object serialization/deserialization in WDDX (Andrei)
- Added krsort() function (Thies)
- Added func_num_args(), func_get_arg() and func_get_args() for standard
access to variable number of arguments functions (Zeev)
- Added FTP support (Andrew Skalski)
- Added optional allowable_tags arguments to strip_tags(), gzgetss() and
fgetss() to allow you to specify a string of tags that are not to be
stripped (Rasmus)
- Upgraded var_dump() to take multiple arguments (Andrei)
- Resourcified XML (Thies)
- Fixed a memory leak in the Apache per-directory directives handler (Zeev)
- Added array_count_values() function. (Thies)
- snmp, pgsql, mysql and gd modules can be built as dynamically loaded
modules (Greg)
- OCI8 fix for fetching empty LOBs (Thies)
- Added user-level callbacks for session module (Sascha)
- Added support for unknown POST content types (Zeev)
- Added "wddx" serialization handler for session module (Sascha)
(automatically enabled, if you compile with --with-wddx)
- Fixed unserializing objects (Thies)
- PHP 4.0 now serializes Objects as 'O' (not understood by PHP 3.0), but
unserializes PHP 3.0 serialized objects as expected. (Thies)
- Made serialize/unserialize work on classes. If the class is known at
unserialize() time, you'll get back a fully working object! (Thies)
- Reworked preg_* functions according to the new PCRE API, which also made
them behave much more like Perl ones (Andrei)
- Made it possible to specify external location of PCRE library (Andrei)
- Updated bundled PCRE library to version 2.08 (Andrei)
- count()/is_array/is_object... speedups. (Thies)
- OCI8 supports appending and positioning when saving LOBs (Thies)
- Added metaphone support (Thies)
- OCI8 doesn't use define callbacks any longer. (Thies)
- OCI8 Driver now supports LOBs like PHP 3.0. (Thies)
- var_dump now dumps the properties of an object (Thies)
- Rewrote the GET/POST/Cookie data reader to support multi-dimensional
arrays! (Zeev)
- Renamed allow_builtin_links to expose_php (defaults to On). This directive
tells PHP whether it may expose its existence to the outside world, e.g.
by adding itself to the Web server header (Zeev)
- Added support for transparent session id propagation (Sascha)
- Made WDDX serialize object properties properly (Andrei)
- Fixed WDDX mem leak when undefined variable is passed in
for serialization (Andrei)
- Added session_unset() function (Andrei)
- Fixed double session globals shutdown crash (Andrei)
- Fixed crash related to ignore_user_abort ini entry (Andrei)
- Added support for external entropy sources for session id creation
(on Unices /dev/random and /dev/urandom) (Sascha)
- Added gpc_globals variable directive to php.ini. By default it is On, but
if it is set to Off, GET, POST and Cookie variables will not be inserted
to the global scope. Mostly makes sense when coupled with track_vars (Zeev)
- Added versioning support for shared library (Sascha)
This allows concurrent use of PHP 3.0 and PHP 4.0 as Apache modules. See
the end of the INSTALL file for more information.
- Added second parameter to array_keys which specifies search value
for which the key should be returned (Andrei)
- Resourcified Informix driver (Danny)
- New resource handling for odbc, renamed to php_odbc.[ch]
- Make set_time_limit() work on Unix (Rasmus)
- Added connection handling support (Rasmus)
- Improved the Sybase-CT module to make use of resources (Zeev)
- Improved the mSQL module to make use of resources (Zeev)
- Changed mysql_query() and mysql_db_query() to return false in case of saving
the result set data fails (Zeev)
- Improved the resource mechanism - resources were not getting freed as soon
as they could (Zeev)
- Added shared memory module for session data storage (Sascha)
- Fixed session.auto_start (Sascha)
- Fixed several problems with output buffering and HEAD requests (Zeev)
- Fixed HTTP Status code issue with ISAPI module (Zeev)
- Fixed a problem that prevented $GLOBALS from working properly (Zeev, Zend
library)
- Ported newest GetImageSize (Thies)
- Added session compile support in Win32 (Andi)
- Added -d switch to the CGI binary that allows overriding php.ini values
from the command line (Zeev)
- Fixed a crash that would occur if wddx_deserialize did not receive
a valid packet (Andrei)
- Fixed a bugglet when redefining a class at run-time (Andi, Zend library)
- Fixed sem_get() on AIX (Sascha)
- Fixed fopen() to work with URL's in Win32 (Andi & Zeev)
- Fixed include_path for Win32 (Andi, Zend library)
- Fixed bug in ISAPI header sending function (Charles)
- Fixed memory leak when using undefined values (Andi & Zeev, Zend library)
- Added output_buffering directive to php.ini, to enable output buffering
for all PHP scripts - default is off (Zeev).
- Fixed some more class inheritance issues (Zeev, Zend library)
- Fixed Apache build wrt to shared modules on FreeBSD/Linux (Sascha)
- Added session.extern_referer_chk which checks whether session ids were
referred to by an external site and eliminates them (Sascha)
- Improved session id generation (Sascha)
- Improved speed of uniqid() by using the combined LCG and removing
the extra usleep() (Sascha)
- Introduced general combined linear congruential generator (Sascha)
- Made ldap_close back into an alias for ldap_unbind (Andrei)
- OciFetchInto now resets the returned array in all cases (Thies)
- Fixed mysql_errno() to work with recent versions of MySQL (Zeev)
- Fixed a problem with define() and boolean values (Zeev)
- Fixed inclusion of gd/freetype functions (Sascha)
- Fixed persistency of MHASH_* constants (Sascha)
- Oracle is now ZTS-Safe (Thies)
- Fixed flushing of cached information to disk in DBA's DB2 module (Sascha)
- OCI8 is now ZTS-Safe (Thies)
- Fixed is_writeable/is_writable problem; they are both defined now (Andrei)
- Imported PHP 3.0 diskfreespace() function (Thies)
- Fixed thread-safety issues in the MySQL module (Zeev)
- Fixed thread-safe support for dynamic modules (Zeev)
- Fixed Sybase CT build process (Zeev)
August 9 1999, Version 4.0 Beta 2
- Fixed a problem when sending HTTP/1.x header lines using header() (Zeev)
- Win32 builds now include the ODBC module built-in (Zeev)
- Fixed SYSV-SHM interface (Thies).
- Updated hyperwave module, made it thread safe
- Updated pdflib module, version 0.6 of pdflib no longer supported
- Updated fdf module
- Built-in phpinfo() links are now turned off by default. They can be turned
on using the allow_builtin_links INI directive (Zeev)
- Changed phpinfo() to list modules that have no info function (Zeev)
- Modified array_walk() function so that the userland callback is passed
a key and possible user data in addition to the value (Andrei)
- Fixed ldap_search(), ldap_read() and ldap_list() (Zeev)
- Fixed Apache information in phpinfo() (sam@breakfree.com)
- Improved register_shutdown_function() - you may now supply arguments that
will be passed to the shutdown function (Zeev)
- Improved call_user_func() and call_user_method() - they now support passing
arguments by reference (Zeev)
- Fixed usort() and uksort() (Zeev)
- Fixed md5() in the Apache module (Thies)
- Introduced build process for dynamic modules (Stig)
- Improved ISAPI module to supprt large server variables (Zeev)
- Imported PHP 3.0 fixes for problem with PHP as a dynamic module and Redhat
libc2.1 in zlib module (Stefan)
- Fixed sybase_fetch_object() (Zeev)
- Made the IMAP module work with PHP 4.0 (Zeev)
- Fixed a problem with include()/require() of URLs (Sascha, Zeev)
- Fixed a bug in implode() that caused it to corrupt its arguments (Zeev)
- Added get_class($obj), get_parent_class($obj) and method_exists($obj,"name")
(Andi & Zeev)
- Fixed various inheritance problems (Andi & Zeev, Zend library)
- Children now inherit their parent's constructor, if they do not supply a
constructor of their own.
- Fixed runtime inheritance of classes (parent methods/properties were
overriding their children) (Zeev, Zend library)
- Fixed backwards incompatibility with the "new" operator (Andi, Zend library)
- Fixed bugs in uksort() and ksort() sort ordering (Andrei)
- Fixed a memory leak when using assignment-op operators with lvalue of type
string (Zeev, Zend library)
- Fixed a problem in inheritance from classes that are defined in include()d
files (Zeev, Zend library)
- Fixed a problem with the PHP error handler that could result in a crash
on certain operating systems (Zeev)
- Apache php_flag values only recognized 'On' (case sensitive) - changed
to case insensitive (Zeev)
- Fixed a memory leak with switch statement containing return statements
(Andi & Zeev, Zend library)
- Fixed a crash problem in switch statements that had a string offset
as a conditional (Andi & Zeev, Zend library)
- Imported PHP 3.0 fixes for rand() and mt_rand() (Rasmus)
- Added function entries for strip_tags() and similar_text() (Andrei)
- Fixed a bug in WDDX that would cause a crash if a number was passed in
instead of a variable name (Andrei)
- Ported strtotime() function from PHP 3.0 (Andrei)
- Merged in gdttf stuff from PHP 3.0 (Sascha)
- buildconf now checks your installation (Stig)
- XML module now built dynamically with --with-xml=shared (Stig)
- Added a check for freetype.h - fixed build on RedHat 6.0 (Zeev)
- Fixed array_walk() to work in PHP 4.0 (Andrei)
- Ported all remaining date() format options from PHP 3.0 (Andrei)
- $php_errormsg now works (Andrei)
- Added locale support for Perl Compatible Regexp functions (Andrei)
- Informix module ported (Danny)
- Removed --with-shared-apache (Sascha)
- Added patch for reverse lookup table in base64_decode (Sascha)
Submitted by bfranklin@dct.com
- Merged in PHP 3.0 version of str_replace (Sascha)
- Added DBA module (Sascha)
- Added session id detection within REQUEST_URI (Sascha)
- Merged in HP-UX/ANSI compatibility switch from PHP 3.0 (Sascha)
- Fixed rpath handling for utilitites built during Apache build (Sascha)
- Added missing E_ error level constants (Zeev, Zend library)
- Fixed a bug in sending multiple HTTP Cookies under Apache (Zeev)
- Fixed implicit connect on the MySQL, mSQL, PostgreSQL and Sybase
modules (Zeev)
- Gave PHP 4.0's SNMP extension all the functionality of PHP 3.0.12 (SteveL)
July 19 1999, Version 4.0 Beta 1
- First public beta of PHP 4.0
+860
View File
@@ -0,0 +1,860 @@
PHP 3.0 CHANGE LOG ChangeLog
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
December 24 1998, Version 3.0.6
- Fix GetImageSize() to work with non-standard jpg images
- Add Mersenne Twister functions (mt_rand, mt_srand, etc)
- Add str_replace() function
- Add chunk_split() function
- Fixed a bug in the memory limit code, in cases where $php_errormsg was
also used.
- Add iptcparse() function
- Adobe FDF supported
- getallheaders() NULL string fix <michale@utko.fee.vutbr.cz>
- Add all configuration directives to phpinfo() page
- Functions pack() and unpack() rewritten to be binary and buffer overrun
safe and behave like the Perl functions for all implemented format codes.
- Ensured that msql_error() will not return error messages generated by
previously-run scripts.
- Add base_convert() function
- Make sprintf() and printf() output binary safe
- Made gzgetc binary safe
- Add convert_cyr_string() and quoted_printable_decode() functions
- Fix ldap_free_result() core dump bug
- Add support for current OpenLDAP-2.0-devel library
- Add php3_asp_tags directive so it can be set from Apache config files
- Added UTF-8 support in the XML extension
- Make rand(min,max) safer on older platforms where the low-order bits have
short cycles.
- Added new pdf (Portable Document Format) module
- Added an XML parsing extension using James Clark's "expat" library
- Optimized parts of the token cache code.
- Terminate on out-of-memory errors. Until now, PHP could crash in out of
memory situations (clean-up, no real effect).
- Unterminated comments in include files were being reported with the wrong line
number. Fixed.
- Added ImageCopy() and ImageColorDeallocate(). ImageCopy() is about
20% faster than ImageCopyResized(). ImageColorDeallocate() marks
palette entries free for reuse (by <mka@satama.com>).
- In the CGI version, it was impossible to access resources (e.g. SQL links,
images) from user-defined shutdown functions. Fixed.
- Added optional third parameter to strpos() to specify the offset to
start searching from.
- Fixed a crash bug in unset() when unsetting illegal variables (rare).
- Made ImageInterlace and ImageTransparentColor parameters optional, and made
them return the current/new settings.
- Optimized GetImageSize() <thies@digicol.de>.
- Made odbc_autocommit() without args return status
- Added connect workaround for OpenLink ODBC
- Added minimal InterBase support. Tested only on 4.0 & Linux.
- Fixed some memory leaks and bogus error messages in the URL handler of
the various file open functions. Should only affect error handling
in bad URLs.
October 5 1998 Version 3.0.5
- mysql_field_flags now reports all MySQL flags and the result is suitable
for automatic parsing. Compatibility warning: The result format has
changed. If you have scripts parsing the result of this function, you
may need to adapt them.
- Made nl2br() binary safe (not that it's of much use).
- Fixed a bug in the API function getThis(). It affected mostly the dir
functions, if nested within objects.
- Fixed a problem in require() in conjunction with switch(), and in some other
cases. Also fixed an identical problem with the call_user_function() API
function.
- Removed -lpthread when compiling with MySQL support. It caused various
serious problems when compiled into Apache.
- Add serialize() and unserialize() functions from jkl@njet.net
- Fix in_addr_t check for systems with in_addr_t in netinet/in.h
- Add atan2() function
September 22 1998 Version 3.0.4
- Added uksort() - array key sort using a user defined comparison function.
- Added 'j' support to date() - generates the day of the month, without
possible leading zeros.
- Added support for multiple crypt() encryptions if the system supports it
- Added optional support for ASP-style <% %> and <%= tags
- Fixed data loss problems with very large numeric array indices on 64-bit
platforms (e.g. DEC UNIX).
- 2 cursor_type parameters for ifx_query() and ifx_prepare changed
to 1 (bitmask). Added a few constants for use in Informix module.
- Added php3.ini option ifx.charasvarchar. If set, trailing blanks
are stripped from fixed-length char columns. (Makes life easier
for people using Informix SE.)
- Static SNMP module which compiles with ucd-snmp 3.5.2
- fixed imap_header & header_info from crashing when a header line
is > 1024 characters.
- Added patch for rfc822_parse_adr to return an array of objects instead
of a single object.
- Informix Online 7.x & SE 7.x support now fairly complete and stable
- Add dbase_get_record_with_names() function
- Added a special case for open_basedir. When open_basedir is set to "."
the directory in which the script is stored will be used as basedir.
- Include alloca.c in the distribution for platforms without alloca().
- Improved stripping of URL passwords from error messages - the length of the
username/password isn't obvious now, and all protocols are handled properly
(most importantly, http).
- Copying objects that had member functions with static variables produced
undetermined results. Fixed.
- Added function lstat() and cleaned up the status functions,
added tests for file status functions (this may break on some plattforms)
- Fixed is_link() - it was returning always false.
- Fixed apache_note() - it was corrupting memory.
- New Function. void get_meta_tags(string filename); Parses filename until
closing head tag and turns all meta tags into variables prefixed with 'meta_'.
The below meta tag would produce $meta_test="some string here"
<meta name="test" content="some string here">
- Generalized some internal functions in order to better support calling
user-level functions from C code. Fixes a few sporadic problems related
to constructors inside eval() and more.
- Fixed an endless loop in explode(), strstr() and strpos() in case of an
invalid empty delimiter.
- rand() now accepts two optional arguments, which denote the requested range
of the generated number. E.g., rand(3,7) would generate a random number
between 3 and 7.
- Added M_PI constant.
- Added deg2rad() and rad2deg() for converting radians<->degrees.
- ImageArc() misbehaved when given negative angles, fixed.
- Fixed a bug in ereg() that may have caused buglets under some circumstances.
- Added imap_status
- Shutdown functions, registered via register_shutdown_function(), could never
generate output in the Apache module version. Fixed.
- Brought IMAP docs into sync with acutal imap code
- imap_fetchstructure now takes in optional flags
- Fix potential core dumps in imap_append and imap_fetchtext_full
- Fix problem in SetCookie() function related to long cookies
- Add uasort() function to go along with usort (like sort() and asort())
- Add port number to Host header as per section 14.23 of the HTTP 1.1 RFC
- Fix imap_reopen to only take 2 arguments with an optional 3rd flags arg
- Add optional 2nd argument to imap_close
- Add CL_EXPUNGE flag to imap_open() flags
- Fix 4th arg on imap_append(). It was getting converted to a long by mistake.
- Fix shutdown warning in the LDAP module
- *COMPATIBILITY WARNING* imap_fetchstructure() "parametres" object and property
name changed to "parameters" to match the documentation and to be consistent
with the rest of the API.
- Delete uploaded temporary files automatically at the end of a request
- Add upload_max_filesize and correponsing php3_upload_max_filesize directive
to control the maximum size of an uploaded file. Setting this to 0 would
completely eliminate file uploads.
- Force $PHP_SELF to PATH_INFO value when running in CGI FORCE_CGI_REDIRECT mode
- Add apache_lookup_uri() function which does an internal sub-request lookup
and returns an object containing the request_rec fields for the URI. (Yes,
you have to be a bit of a gearhead to figure this one out)
- Fix a few signed char problems causing functions like ucfirst() not to work
correctly with non-English charsets
- md5() function not binary safe - fixed
August 15 1998 Version 3.0.3
- Changed the name of fopen_basedir to open_basedir, to be a little more
accurate about what it does.
- Added Hyperwave module
- Added config-option (php3_)enable_dl <on/off>. This enables/disables the
dl() function. In safe-mode dl() is always disabled.
- Auto-prepended files were crashing under some circumstances - fixed.
- Win32 mail fixes provided by walton@nordicdms.com
- Comparing between arrays and/or objects now generates a warning (it always
returns false, as it used to; no comparison is made)
- Fixed a bug in the syntax highlighting code, that made ending-double-quotes
appear twice under certain circumstances.
- Fix bug in filetype() function related to symlinks
- Started integrating Informix SE support to PHP configure/makefile setup.
- gdttf roundoff fixes from ellson@lucent.com
- Added initial Informix SE support files from Danny Heijl - This code still
needs to be integrated into the PHP configure/makefile setup and the code
itself needs more work.
- return in the global scope now terminates the execution of the current file.
- Added the ability to register shutdown function(s), via
register_shutdown_function($function_name).
- Clean up const warnings
- Add write support to ftp fopen wrappers
- Add strspn() and strcspn() functions
- On systems without strerror use Apache version if compiling as Apache module
- The PHP start tag was being ignored under some circumstances - fixed.
- The db, dbase and filepro functions are now Safe-Mode aware.
- Added config-option (php3_)fopen_basedir <path>. This limits the directory-
tree scripts can open files in to <path>.
- Fixed pg_loreadall that didn't always return all the contents in a PostgreSQL
large object. Also, doesn't pass through anything if method is HEAD.
- configure fix to create target Apache module dir
- Fix core dump in imageTTFtext() function
- Added static IMAP support
- Syntax highlighting was generating additional whitespace - fixed.
- Added ucwords. Works like ucfirst, but works on all words within a string.
- Added array_walk() - apply user function to every element of an array
- Added usort() - array sort that accepts a user defined comparison function!
- Added the ability to call user-level functions and object methods on demand
from the C source using a completely generalized, slick API function.
Miracles do happen every once in a while.
- Added constructors. Don't even squeek about destructors! :) (we mean that)
- Make pg_lowrite() binary safe
- Fixed mod_charset option in ./setup
- Fixed rewinddir() and dir()::rewind() under Win32 (they didn't work before).
- Add Win32 COM support! By-name referencing is supported using the IDispatch
interface (automation). Available functions - COM_Load(), COM_Invoke(),
COM_PropGet() and COM_PropSet().
July 20 1998 Version 3.0.2a
- Fix a quirk in the configuration file parser, the endless fountain of joy
and fun.
- Fix a bug in the API function add_method() that made dir() crash.
July 18 1998 Version 3.0.2
- Compile cleanups for *BSD
- Add support for the OpenLink ODBC Drivers
- Add PHP_SELF, PHP_AUTH_* and HTTP_*_VARS PHP variables to phpinfo() output
- Add workaround for broken makes
- Add Apache 1.3.1 support (some Apache header files were moved around)
- Added apache_note() function.
- Fix order of system libraries and detect libresolv correctly
- Fixed a bug in the Sybase-DB module. Several numeric field types were
getting truncated when having large values.
- Added testpages for unified odbc
- Fix php -s seg fault when filename was missing
- Made getdate() without args default to current time
- Added ImageColorResolve() and some fixes to the freetype support.
- Added strcasecmp()
- Added error_prepend_string and error_append_string .ini and .conf directives
to make it possible to configure the look of error messages displayed by PHP
to some extent
- Added E_ERROR, E_WARNING, E_NOTICE, E_PARSE and E_ALL constants, that can be
used in conjunction with error_reporting()
(e.g. error_reporting(E_ERROR|E_WARNING|E_NOTICE);
- Fixed a crash problem with classes that contained function(s) with default
values.
- Fixed a problem in the browscap module. Browscap files weren't being read
properly.
- Fix -L path in libphp4.module to make ApacheSSL compile without errors
- Fix StripSlashes so it correctly decodes a \0 to a NUL
July 04 1998 Version 3.0.1
- echo/print of empty strings don't trigger sending the header anymore.
- Implemented shift left and shift right operators (<< and >>)
- Compile fix for cc on HP-UX.
- Look for beta-version Solid libraries as well.
- Make GD module show more info in phpinfo().
- Compile fix for NextStep 3.0.
- Fix for Oracle extension on OSF/1.
- Fix gd 1.3 bug in ImageColorAt().
- pg_loread() hopefully handles binary data now.
- Turned off some warnings in dns.c
- Added ImageTTFBBox() and made ImageTTFText() return bounding box.
- Added constants for Ora_Bind()'s modes.
- Renamed all hash_*() routines to _php3_hash_*() to avoid clashes with other
libraries.
- Changed uodbc default LONG behaviour: longreadlen 4096 bytes, binmode 1.
The module now actually uses the php.ini settings.
- New PostgreSQL functions: pg_fetch_row(), pg_fetch_array()
and pg_fetch_object()
- Fix a segmentation fault when calling invalid functions in certain
circumstances
- Fix bug that caused link-related functions to not pay attention to
run-time safe mode setting (it was using whatever was set at compile time).
- Fix bug in exec() function when used in safe mode
June 6 1998 Version 3.0
- Add checkdnsrr function (check availability DNS records)
- Add getmxrr function (get MX hostnames and weights)
- Fixed bug in nl2br() function
- Fix for an RC5 related problem in the Sybase module, when dealing
with very long data types.
- Speed up string concatenation by roughly a factor of 2
- Add escape-handling to date function
- Make base64 functions binary safe
- Add strrpos function to complement strpos function added in RC5
- Add ltrim function (strips only at the start of string)
- Add rtrim as an alias to chop() for completeness sake
- Add trim function (similar to chop, except it strips at the start as well)
- Added 2 optional args to fsockopen function - errno and errstr
- Fixed bug in split() function related to leading matches
- Fixed problem in error_log() function (thanks to Jan Legenhausen)
- empty("0") was returning true - fixed
- Removed the old sybsql module. Use the new sybase_*() functions instead.
- Several fixes to the configuration file parser
- LDAP fixes - fixed return values on several functions
May 23 1998 Version 3.0RC5
- The BC math library functions now compile in by default.
- Fixed a bug in virtual() and other types of SSI's (e.g. <!--#exec). Under
certain circumstances, this used to result in random problems.
- Fixed a bug in virtual(). It was misbehaving if it was called before any
other output.
- Added mysql.default_port, mysql.default_host, mysql.default_user and
mysql.default_password ini-file directives.
- Improved handling of the MySQL default port. It now honors /etc/services
and $MYSQL_TCP_PORT.
- Fixed a crash in opening of broken ftp:// URLs, and improved error reporting
in opening of URLs.
- Fixed several non-critical scanner issues with syntax highlighting mode and
the <script language=php> tag.
- Fixed fseek on windows. (windows only): fseek will not return proper results
on files opened as text mode. PHP uses binary mode as the default for file
operations, but this can be overiden by fopen. Do not open files in text
mode and use fseek on them!
- Add strpos() function
- Added zlib module, requires zlib >= 1.0.9
- Improved the module API implementation. Dynamic modules may now register
persistent resources (not that it makes much sense, but at least PHP
won't crash). The API itself remains unchanged.
- bcmod() wasn't always behaving like modulus should behave (it was behaving
exactly like GNU bc's % operator). Fixed.
- Changed the Sybase-DB module to always return strings, instead of auto-typing
result sets. This was done for consistency with the other database modules,
and in order to avoid overflows due to the platform-dependant limitations
of the numeric data types of PHP. You can turn compatability mode on using
the sybase.compatability_mode directive in the php3.ini file.
- Fixed problems with the TINYINT field in the Sybase-CT module.
- Applied some small speed optimizations to the Sybase-DB module querying code.
- Added 'numeric' and 'type' properties to the object returned by
sybase_fetch_field().
- The 'new' operator doesn't accept all expressions anymore. Instead, it
accepts a class name, or a variable reference (scalar, array element, etc).
- Add ora_numcols() function
- Add ora_do() and ora_fetch_into() functions to Oracle driver
- Add persistent connection support to Oracle driver
- Make Oracle driver clean up open connections and open cursors automatically
- Added fread() and fwrite() that properly handle binary data.
- Add Ora_ColumnSize() to Oracle code
- The string "0" means FALSE again. This was done in order to maintain type
conversion consistency.
- Added solid_fetch_prev() for fetching the previous result row from Solid.
- Huge integers are now automatically converted to floating point numbers
(that have a wider range).
- Floating point numbers are now displayed using scientific notation when
they're extremely big or extremely small. The 'precision' php3.ini directive
no longer designates the number of decimal digits, but rather, the maximum
number of significant digits required.
- Added support for scientific notation for floating point numbers (e.g. 1E7)
throughout the entire language.
- Fixed a potential/probable memory corruption problem with HEAD request
handling.
- Using un-encapsulated strings now generates a NOTICE-level warning
(e.g. $a = foo; instead of $a = "foo";)
- Added defined("name") function to check if a certain constant is defined
or not.
- Support new Apache mechanism for setting SERVER_SUBVERSION
- Added PHP_OS and PHP_VERSION constants
- Added the ability to define constants in runtime! Constants are script-wide,
(there's no scope, once the constant is defined, it's valid everywhere).
Syntax is define("name", $value [, $case_insensitive]). 'name' can be any name
that is a valid variable name, *without* the $ prefix. 'value' can be
any *scalar* value. If the optional 'case_insensitive' parameter is 1,
then the constant is created case-insensitive (the default is case
sensitive). Note: define() is currently *NOT* supported in preprocessed
scripts.
- Added general support for constants. The Syslog constants (e.g.
LOG_ERR, LOG_CRIT, etc.) should be accessed as constants from now on (that
is, without a $ prefix). You can still set define_syslog_variables to On
in the php3.ini file if you want to define the various $ variables. The
default for this directive in the php3.ini-dist file has been changed to
Off.
- The configuration file path variable now expands . and .. into their
respective directories. You can obtain the path of the php3.ini file
that was used by printing get_cfg_var("cfg_file_path").
- Fixed a crash-recovery parser crash ($a=7; $a[3]+=5;)
- Add gmmktime() function
- Fixed a crash with implode() and empty arrays.
- Fixed a bug that, under fairly rare circumstances, caused PHP not to
recognize if(), require() and other statements as statements, and
to complain about them as being unsupported functions.
- Beautified php3.ini-dist and added more comments to it. Also changed
the behavior of the configuration file parser to be brighter about
the various constants (TRUE/FALSE/ON/OFF etc).
- Fixed a bug in openlog() - the specified device name was being mangled.
- Memory leaks were sometimes reported erroneously - fixed.
- Improved the convertor to handle some quirks of the PHP/FI 2 parser with
comments.
- Fixed number_format() to properly handle negative numbers, and optimized it
a bit.
- Fixed static variables inside class member functions. Note that using such
static variables inside member functions usually defeats the purpose of
objects, so it is not recommended.
- Fixed a bug in fpassthru() (the file was being closed twice).
- Added strftime().
- Add set_socket_blocking() function to control blocking on socket fd's
- The sendmail_path in php3.ini was being ignored - fixed.
- Fixed a bug with file upload, with files that contained the MIME boundary
inside them.
- Fixed a bug with form variables of type array, with spaces in their
index (e.g. name="foo[bar bar]").
- gd-1.3 autodetect and support
- Year 2000 compliance is now togglable from the php3.ini file. Setting PHP
to be y2k compliant effects the way it creates cookies, and means it'll
NOT work with many browsers out there that are not y2k compliant! For
that reason, the default for this option is off.
- safe mode / fix from monti@vesatec.com
- Integrated the FreeType support in the GD extension.
- Added --with-gd=DIR and --without-gd options to configure
April 18 1998 Version 3.0 Release Candidate 4
- Auto-prepended and auto-appended files were reporting the wrong filename
in errors and in __FILE__ - fixed.
- Fix GPC problem related to mixed scalar and array vars with the same name
- Made putenv() Apache-safe. Environment variables may no longer leak in
between requests.
- The trailing semicolon is no longer required in class declarations.
- Fixed a memory leak in the (array) and (object) operators under certain
conditions.
- <script> tags weren't working unless short tags were enabled - Fixed.
- Fixed a bug in certain array indices that weren't treated as numbers
even though they looked like numbers (e.g. "10", "20").
- Changes to support renamed API functions in Apache-1.3
- Fixed the -p and -e command line switches
- Fix a segfault when calling command line version without parameters
- Fix for feof() when used on a socket
- Fix off-by-one error in fgets() when used on a socket
- Fix bug in ImageSetPixel() (Thanks to ecain@Phosphor.net)
March 31 1998 Version 3.0 Release Candidate 3
- Tiny bugfix for magic_quotes_sybase
- Fix Apache build problems introduced in RC2
- $a["0"]==$a[0] fix
- Apache-1.3 build changes to support 100% automatic builds and shared library
module builds. See INSTALL file.
March 30 1998 Version 3.0 Release Candidate 2
- Changed the socket implementation under UNIX to not use FILE pointers, in
order to work around the buggy Solaris libc (and possibly buggy libc's
in other platforms).
- Fixed a bug in min() and max() with certain arrays.
- *WARNING* Move Apache 1.3 php3 file install to src/modules/php4 instead of
src/modules/extra. Make sure you change your AddModule line correctly
in your Apache Configuration file. This change is to take advantage of
new Apache-1.3 configuration mechanism which makes it easier to build an
Apache server with PHP automatically enabled. It will also help building
a shared library module version of PHP soon.
- Fixed a crash bug with auto-appended files.
- Made --enable-discard-path work on all Unix servers #!/path/php CGI scripts
should now work everywhere. I have tested on Apache, WN and Netscape 2.0
- Made $a["123"] and $a[123] be identical. $a["0123"] is still different,
though.
- Added 'precision' ini directive, to set the number of decimal digits
displayed for floating point numbers (default - 6).
- Made integer/integer divisions evaluate to floating point numbers when
applicable (e.g., 5/2==2.5(float), but 4/2==2(int))
- Get rid of reliance on tied streams and move all socket reads and writes
to recv/send calls
- Cleaned up head.c a bit and fixed CGI SetCookie order problem
- Changed default variable parsing order to Get-Cookie-Post (GPC)
- Fixed setup so it has all configure options and defaults.
- Added optional decimal point and thousands seperator to number_format()
e.g., number_format(1500,2,',','.') == 1.500,00
- Fixed cgi bug in windows that prevented files from being parsed on many
systems and servers.
March 23 1998 Version 3.0 Release Candidate
- Added support for the Raima database (ALPHA)
- Fixed a bug in persistent PostgreSQL links and the connection-string method.
- Added EXTENSION_STATUS file, that specifies the stability and status of
every module in the distribution.
- Added optional parameters to user functions with default values, variables
that are forced to be passed by reference and variables that can be
optionally passed by reference. The ini file directive
'ignore_missing_userfunc_args' is no longer supported.
- Added fhttpd support (by Alex Belits)
- Improved performance by approximately 20-30%.
- Added mysql_error(), mysql_errno() (if available) and msql_error().
Errors coming back from the database backend no longer issue warnings.
Instead, use these functions to retreive the error.
- Patched count(), each(), prev(), next(), reset() and end() to work around
the implementation side effects of unset(). As far as the users are
concerned, this should be transparent now (even though it's slower now,
until it's thoroughly fixed in 3.1).
- Added number_format(). number_format(2499,2)=='2,499.00'.
- error_reporting() now sets the error reporting level to the supplied
argument, without any interpretations.
- Fixed a lookahead parser bug that occured under rare circumstances.
- Change the comparison operators to compare numeric strings as numbers. If
you want to compare them as strings, you can use the new C-like strcmp()
- Fixed Ora_GetColumn() bug when fetching strings
- Added Ora_ColumnName() and Ora_ColumnType()
- Preliminary LONG and LONG RAW support in Oracle extension
- Add \123 and \xAB style octal and hex escapes to "" and `` strings
- Add "-c" command line flag for specifying path to php3.ini file
- Improved list() so that elements can be skipped, for example:
list($name,,,$realname) = explode(":",fgets($passwd_file));
- Fixed a tiny bug in the hash initialization which caused excessive use of
memory. Report and fix by short@k332.feld.cvut.cz
- Fixed strtolower() and strtoupper() to work with 8-bit chars
- Fixed to compile and run on SunOS 4.1
- Fixed a crash in soundex() of an empty string
- Fixed parse_str() - it wasn't always defining the right variables,
and didn't work with arrays.
- Made [m,My]SQL create/drop database functions return success status
- Fixed some memory leak/crash problems in the Adabas module
- Added each() in order to allow for easy and correct array traversing.
- Make Apache module version respect LOCALE setting
- Add support for Apache 1.3b6+ ap_config.h file
- Fixed a nasty corruption bug in eval() and show_source() that resulted in
script termination (e.g. eval("exit();").
- Fixed a syntax highlighting problem with keywords used as variable
names.
- Fixed a possible crash and/or file descriptor leak
- Fixed line number being off by one in #! shell style execution
- Made it possible to disable auto_prepend/append with "none" filename
- Allow safe CGI calling through #!php style scripts
March 2 1998 Version 3.0b6
- Made [s]printf handle %ld
- Changed CGI version to only open regular files as input script
- Added ignore_missing_userfunc_args directive to suppress warnings messages
about missing arguments to user-defined functions
- Added Postgres function - pg_cmdtuples(), by Vladimir Litovka
- Disabled command line options if used as CGI
- Changed CGI version to use PATH_TRANSLATED as the script file name
- Link with solid shared library instead of static one
- Fixed a crash with functions that aren't being called correctly
- Fixed file descriptor leak in auto-prepend/append
- Imap module is usable. See README in dl/imap.
February 24 1998 Version 3.0b5
- Made the URL aware file functions be enabled by default
- Fixed an unlikely crash bug in the parser, with uninitialized array elements
which are refered to as objects.
- Fixed several fields that were being incorrectly read in Sybase CT.
- Fix Apache-1.3 related SIGHUP problem which was preventing php3.ini from
getting re-read on a SIGHUP
- *** WARNING *** Downwards incompatible change: The plus operator (+) is not
longer overloaded as concatenation for strings. Instead, it converts its
arguments to numbers and performs numeric addition.
- Add Stig and Tin's bdf2gdfont script to extra/gd directory
- Added join() as an alias to implode()
- Made implode() accept arguments in the order used by explode() as well
- Made $php_errormsg local in function calls
- Fixed Apache configuration directive bugs
- Added a number of .ini directives to Apache .conf directive list
- Fixed a 'memory leak' with strtok()
- echo/print now handle binary data correctly.
- NEW now accepts any expression for the class name argument.
- Add ImageDashedLine() GD function
- Add arg_separator .ini directive so the '&' GET method separator can be
changed to ';' for example. Corresponding php3_arg_separator Apache .conf
directive works as well.
- Walked around an implementation side effect of switch(). <? switch(expr) { ?>
now works.
- Added memory caching, resulting in a significant performance boost
- Added support for for(): .. endfor; loops
- Added a new predicate - empty($var). Returns true if $var is not set,
or is FALSE. Returns false otherwise.
- Added is_integer() (same as is_long()) and is_real() (same as is_double()).
- Added sizeof() as an alias to the count() function
- Added --enable-force-cgi-redirect, to prevent the CGI from working if
someone directly accesses PHP not through Apache's CGI redirect
(off by default).
- Fixed marking of deleted dBase records. Noticed by Simon Gornall
<simon@oyster.co.uk>.
- Fixed fixed "%%" bug in [s]printf
- Fixed a UMR (initialized memory read) in the Oracle code
- Potential fix for mysql-related SIGPIPE problem which caused httpd to spin
- Made PHP responsive to the Apache link status (stop executing if the link
dies).
- Fixed a crash bug with StrongHold and secure pages
- Fixed StrongHold installation
- Optimized the function call sequence a bit.
- Fixed Sybase/CT date/datetime/money fields work to correctly.
- Fixed Apache module startup problems - php3_module_startup should only be
called once.
- Fixed ord() with characters >127
- Fixed bug in file_exists() function
- Fixed stripslashes() to remove the escaping quote (instead of backslash)
in case magic_quotes_sybase is true.
- Also make echo and print automatically remove trailing decimal zeros.
- Added htmlentities(), currently handling only ISO-8859-1 entities
- "0" is no longer considered false, the only string which is false is the
empty string "".
- Added 'true' and 'false' keywords
- Added 'xor' (logical exclusive or)
- Automatic conversion from double to string removes decimal trailing zeros.
- Added arsort() and rsort() to sort in descending order.
- Turned on "XLATOPT_NOCNV" by default for uODBC/Solid.
- Added support for a port number in the mysql_(p)connect() functions
- Fixed a file descriptor leak in the configuration parser.
- Fixed a few buglets with syntax highlighting with certain language keywords
- Added functions to control minimum severity level of Sybase messages to
display.
- Added highlight_string() - behaves like highlight_file(), only instead
of highlighting a file, it syntax highlights the contents of its
argument.
- Renamed show_source() to highlight_file(). show_source() is still
supported for downwards compatability.
- Fixed a bug in class inheritence - member functions with upper case
letters in their names couldn't be redefined.
- Made chown(), chgrp() and chmod() return TRUE/FALSE instead of 0/-1.
February 02 1998 Version 3.0b4
- Fixed a segfault bug in one of the unified ODBC error messages.
- Set default file modes to binary on Win32 (solved a lot of bs)
- Fixed file copy on Win32
- MIME file uploads fixed on Win32
- Added contributed icons by Colin Viebrock (undex extra/icons)
- Fixed the debugger enough to call it "beta code".
- Fixed some leaks in the Oracle module, tidied up the code a bit.
- Added __FILE__ and __LINE__ which evaluate to the currently parsed file
and currently parsed line respectively.
- Added ImageColorAt(), ImageColorSet(), ImageColorsForIndex(), and
ImageColorsTotal() to allow manipulating the palette of GIF images.
- Rename '--enable-url-includes' option to '--enable-url-fopen-wrapper' to
better describe what it does, and pay attention to the setting.
- Added optional parameter to the file(), readfile() and fopen() functions
to look for files located in the include path.
- Fixed bug that allowed the file() and readfile() to open files in the
include path inadvertantly.
- Fixed a (documented) bug in printf()/sprintf() with hard limited strings
and alignment (e.g. %-.20s).
- Optimized several quoted string routines.
- Added error_log ini directive to select where errors get logged when
log_errors is turned on or the error_log() function is used.
- Added the ability to direct errors to log files instead of or in addition
to the script output. Use the new display_errors and log_errors
php3.ini directives.
- Made environment variables uneraseable by POST/GET/Cookie variables.
- Fixed a bug in the elseif() construct. The expression was being evaluated
even if a previous if/elseif already evaluated to true and got executed.
- Fixed a bug in the exit code parameter of system()
- Tighten up all exec() related functions in safe mode
- Added error_log() function to log messages to the server error log, or
stderr for the CGI version.
- Added support for a general memory limit of scripts.
- Fixed a segfault bug that occured under certain circumstances with shell
escapes ($foo = `...`)
- Made keywords be valid property names of objects.
- Fixed a segfault bug when creating new objects of an unknown class.
- Fixed a problem with the maximum execution time limit, that may have
prevented this feature from working on certain platforms.
- PHP would now warn you with E_NOTICE about unknown escape characters,
e.g. "\f". It would still be considered as a backslash followed by f,
but the proper way of writing this is "\\f" or '\f'.
- Added support for ${...} inside encapsulated strings. Supported: ${foo},
${foo[bar]}, ${foo[0]}, ${$foo[$bar]}, ${$foo->bar} and ${$foo}
- Fixed a bug in automatic persistent link reconnect of the Sybase/DB module.
Thanks to Steve Willer for finding that 'stealth' bug!
- Fixed a crash bug in the GET/POST/Cookie parser in case of regular
and array variables with the same name.
- Added round() function.
- Can't use encapsed strings as variable names anymore, ie. $"blah blah".
- Fixed bug in gethostby*() functions that resulted in a core dump.
(Noticed by torben@coastnet.com.)
- Fixed bug in dbase_get_record that prevented number and date fields
from being properly decoded. (Thanks again to colins@infofind.com.)
- Make dbase_get_record include a 'deleted' field that indicates whether
that record had been marked for deletion.
- Fixed bug in dbase library that stomped on the deleted flag of the first
record in the file if it was set. (Thanks to colins@infofind.com.)
- Fixed putenv() to not report a memory leak and possibly prevent a bug
from that memory being freed.
- Added setlocale()
- Added pg_fieldisnull() (by Stephan Duehr)
- Changed pg_exec() to always return a result identifier on succees
- Solid linking fixes (tries to find the right library)
- Fixed a but with date() and the 'w' element.
- Tried to eliminate unimportant memory leak notifications.
- Made min() and max() backwards compatible and able to handle doubles.
- Add fgetc() function
- Fixed bug in getmyuid(), getmyinode() and getlastmod(). Thanks to
khim@sch57.msk.ru for pointing this out.
- Fixed http:// URL includes with no path specified send request for /.
- Added GetAllHeaders() (Apache-only)
- Added workaround that made the Image text functions 8-bit clean
- Made snmp internally compilable for Win32 (not the unix one though),
only adds 2k to binary size, so no reason not to have it there.
- Fixed ldap loading on Win32
- Fixed MySQL Info function on Win32 platform
- Fixed compilation of syntax highlighting mode
January 17 1998 Version 3.0b3
- Added mysql support under windows ;) happy happy joy joy
- Fixed dbase.dll for Win32 to actualy load now.
- Enhanced the convertor to recognize ?> as a php-close-block as well.
- Fixed potential SetCookie() core dumps
- Changed print to be an expression instead of a statement. That means you can
now do stuff like foobar() or print("Unable to foobar!"). echo has NOT been
changed.
- Removed the flex optimization flags to reduce the size of the scanner
- Added memory leak logging into apache log files (apache module only)
- Fixed a nasty bug in one of the internal stacks. This may have caused
random crashes in several occassions.
- Fixed bug in ImageGif() making it hang sometimes
- Added ImageLoadFont(), ImageFontWidth() and ImageFontHeight()
- error_reporting() now returns the old error reporting level
- Fixed url includes/opens not working under Win32
- Fixed errorneous handling of multipart/form-data input
- Added rawurlencode(), rawurldecode() and changed urlencode() and urldecode()
a bit too.
- Fixed a bug in [s]printf, sign was forgotten for doubles.
- Fixed a segfault bug in pg_fieldprtlen(), and made it accept field names
in addition to field offsets.
- Made the setup script a little more user-friendly.
- Added is_long(), is_double(), is_string(), is_array() and is_object()
- Fixed a bug in freeing of mSQL results.
- Improved pg_exec() to properly return true or false with queries that don't
return rows (i.e. insert, update, create, etc)
- Added get_cfg_var() to enable checking cfg file directives from within
a script.
- Fixed a bug with urlencode() and characters 0x80-0xff
- Changed the behaviour of ereg_replace to more intuitive. The
backslashes other than valid existing back references in the second
argument are no more evaluated as escape sequences.
- Fixed a bug in the configuration file loader and safe mode.
- Fixed a bug with configuration variables taken from the environment.
- Added <script language=php> </script> as PHP open/close tags, to allow
the use of editors such as Microsoft Frontpage.
- Fixed a bug in the default php3.ini directory - it wasn't defaulting to
/usr/local/lib properly.
- Added support for \r\n line endings
- Fixed a bug that may have prevented POST method variables from working
with certain scripts when using the CGI version.
- Convertor: Added support for single-quoted strings
- Fixed segfault bug in the Adabas module, with queries that don't return
rows (update, insert, etc).
December 22 1997 Version 3.0b2
- Changed variable type conversions that do not specify base to always use
base 10. "010" is no more 8, it is 10. Use intval ($x, 0) to get C-style
octal and hex numbers recognized.
- Fixed a possible segfault bug in several functions, when using the concat
operator and possibly other operators/functions.
- # is no longer accepted as a comment in php3.ini. Use ; instead.
- Added browscap support
- Configuration file directives are now case-sensitive
- Fixed msql_tablename() and msql_dbname()
- Added a PHP/FI 2.0 -> PHP 3.0 convertor
- Added support for shell/perl-style single quotes
- Added support for execution of external programs using backquotes ($a=`ls -l`)
- fixed mail() on windows, also fixed memory leaks in mail on windows
- added sendmail_from to handle return route on windows
- Changed the way the config file is searched. The file name is now
php3.ini (hardcoded), and it'll be looked for in: local directory, $PHPRC
and builtin path designated by ./configure under UNIX or Windows directory
under Windows.
- Fixed ereg_replace replacing empty matches and a one off buffer overflow
- Fixed File upload on windows platform
- Fixed a bug that caused 'HTTP/1.1 100 Continue' messages with
Internet Explorer 4.0 and certain scripts that receive POST variables
- Get/POST/Cookie data variables are from now *ALWAYS* strings. If you want
to use them in integer/real context, you must explicitly change their types.
This was done in order to avoid possible loss of data when doing these
conversions automatically.
- Variables named as keywords are now allowed (e.g. $function, $class, etc)
- Fixed a problem with msql() and mysql() with NULL fields
- Fixed a segfault bug with class declarations
- Fixed bugs with FOR loops and include() from within eval()
- Changed include() to be executed conditionally. PHP-3.0 efficient
unconditional include is now require()
December 08 1997 Version 3.0b1
- Switched to public beta test phase
- Generalized unset() and isset() to work on any type of variables, including
specific array indices or object properties (e.g., unset($a[4]) now works).
- Added support for object references inside encapsulated strings
(for example, 'echo "Username: $user->name"' now works)
- Added arbitary precision math support (basic operations with
unlimited range numbers, and support for unlimited decimal digits)
- Apache module can now handle preprocessed scripts (by using:
AddType application/x-httpd-php3-preprocessed .php3p
in the Apache configuration)
- Made settype() pass its first parameter by value. Improved it to be able
to convert to arrays and objects (originally by Steve Willer)
- Implemented CPU time limit on scripts when setitimer() is available
- Computed field names in the Sybase/CT and Sybase/DB modules are now named
computed, computed1, computed2, ...
- Added Sybase/CT client/server message handlers and updated the Sybase/DB ones
- Made the regexp function automatically take arguments by reference
when necessary
- Added builtin support for auto append and prepend in the parser level
- Improved the Sybase/CT sybase_query(). Should be more stable now, and
hopefully work with a wider range of queries. It's difficult to work
without docs, though, so it may still not be 100% right...
- Changed error messages to show error type, file and line with bold
- Added support for autoprepend and autoprepend
- Added some more warning flags if gcc is used
December 03 1997 Version 3.0a4
- Improved the internal functions API - no need to explicitly pass
parameters by reference to internal functions that specifically
require them, e.g. sort(), ksort(), reset(), count(), etc.
This is *STILL* downwards compatible with the previous alphas,
in the sense that you can explicitly pass the arguments by reference
if you want to.
- use srandom/random instead of srand/rand if available
- Added [m,My]sql_listfields() for downwards compatability
- -p now replaces .php3 extension with .php3p (otherwise it adds .php3p)
- Added C++ style comments (// comment)
- Fixed # commenting to terminate at a close PHP tag
- Added \0 back reference for full string match to *reg*_replace and
added backslash escaping to replace string
- Fixed a few bugs in the Sybase DB-library module.
- Added Sybase CT-library support. It should be considered experimental.
Syntax is identical to the one of the DB-library. Allows people to
connect to MS-SQL servers from Linux without having to pay for a
library!
- Beautified phpinfo()
- Add ImageColorClosest() and ImageColorExact() GD functions
- Make all .ini directives work as Apache .conf directives as well
- Added PHP2-like File() function with PHP3 URL support
- Upgraded the Sybase interface. It's practically MySQL compatible now!
Among other things, added sybase_fetch_array() and sybase_fetch_object().
- Fixed problem in multi dimensional array handling and self modifying
operators (+=, -=, etc).
- Safe Mode file open implementation
- SVR3 portability problem fix
November 23 1997 Version 3.0a3
- Made the global statement behave like PHP 2 with undefined variables
- Added msql_fetch_object() and msql_fetch_array()
- Switched between the 1st and 2nd parameters to explode(), so that it acts
like split()
- Fixed passthru(), exec() and system() functions
- Implemented second optional parameter to intval() to specify conversion base
(The default is to assume you want to do a base 10 conversion.)
- Implemented SQL safe mode for MySQL
- Read UploadTmpDir from php3.ini instead of apache conf files
- Added mysql_fetch_object() and mysql_fetch_array()
- Changed function->old_function. function is now an alias to cfunction.
- Split the magic_quotes directive to get/post/data and other
- Added generic copy() function
- Added a $GLOBALS[] array, which contains all global variables
- Fix broken getimagesize() function
- Made mysql_fetch_field() and msql_fetch_field() optionally accept a 2nd argument
- Fixed mysql_data_seek() and msql_data_seek()
- Changed list assignment to list(...) and array init to array(...)
- Made <?php_track_vars?> work
- cgi when not in debug mode uses regular malloc(), free() functions now
- Added preliminary support for perl-style list assignments
- Fixed a bug in mysql_result() and msql_result() when specifying table
- renamed internal error-handling function and levels
- Added basename and dirname functions similar to sh counterparts
- Added base64_encode() and base64_decode()
- Support Basic authorization for http url includes
- Added parse_url() function to extract url components
- Made it possible to use anonymous ftp on URL includes
- Fixed url includes to handle different URLs better
- Fixed mysql_field*() functions
- Made mysql_connect() smarter, after a mysql_close() (applies to msql and pgsql too)
November 6 1997 Version 3.0a2
- Fixed a segfault bug caused by non-persistent connect in [m,My,Postgres]SQL modules
- Fix command line argument handling
- Made empty array list assignments work ($a=({});)
- Made '$' escaping optional when a variable name parsing isn't possible
- Added support for mysql_[p]connect(host) and mysql_[p]connect(host,user)
- New layout in phpinfo()
- Update Oracle extension to use php3_list functions
- Add includepath support
- Add #!php shell script escape support
- Change name of CGI/command line version from php3.cgi to php
- Add SNMP extension
- show_source() support
- Parsing of command-line args for CGI version
- Support for backreferences in ereg_replace
- Support for hexadecimal numbers directly at the scanner level
- Support octal numbers directly at the scanner level
- Fixed problem with huge html files (with little or no php code)
- Fix eval() empty string argument core dump
- renamed 'install' to 'setup' to be more accurate and avoid name conflict
- Fixed Oracle compilation
- Fixed mSQL 1.0 compilation
- Fixed a problem in the mSQL, MySQL and PostgresSQL drivers and NULL fields.
- Fixed the GLOBAL statement to be able to declare an array.
October 29 1997 Version 3.0a1
- Start with excellent new parser from Andi and Zeev
+75
View File
@@ -0,0 +1,75 @@
This is the ChangeLog from PHP3 as of Apr 12 1999.
Entries should be removed from this file, if you transfer changes
over to PHP4.
============================================================================
?? 1999, Version 3.0.8
- added Oracle-OCI8 persistent connections
- fixed OCIDefineByName crash.
- fixed some NULL-column related problems in OCI8-module.
- Some Informix driver improvements.
- PUT method support (mlemos@acm.org)
- Fix parameter count problem in odbc_setoption()
- Really fix implode() this time. The fix in 3.0.7 was bogus
- Make fgetss() slightly smarter
- Add strip_tags() which uses the fgetss state-machine but acts on a string
March 1 1999, Version 3.0.7
- Added pdf_put_image and pdf_execute_image
- Initial work on an ImageMagick module - doesn't do anything yet
- Make configure script detect Netscape's LDAP SDK automagically
- Fixed Oracle-OCI8 module for windows.
- Add OCIRowCount function. (Number of affected rows for update-statements)
- Add OCIDefineByName function.
- Change the behaviour of open_basedir. It's now possible to supply more
than one directory. open_basedir paths from parent directories are now
automatically inherited.
- fix rand() and mt_rand() to make the ranges work correctly
- htmlspecialchars() and htmlentities() are now binary safe.
- Add extract() function.
- Oracle-OCI8 driver now supports BLOBS/CLOBS and IN/OUT binding of local php
variables.
- Clean up apxs build
- Add INSTALL.REDHAT file to walk RedHat users through the install
- Add function_exists() function.
- Add another version of WDDX module
(we need to pick a single implementation here)
- Fixed includes for iODBC to support both the old and the new LGPL version
- Fix implode() bug - When imploding an array that contained unset() elements
it wasn't correctly skipping past these
- Add connection_status() function. This returns the raw bitfield which
indicates whether the script terminated due to a user abort, a timeout
or normally. Note that if ignore_user_abort is enabled, then both the
timeout state and the user abort state can be active
- Add connection_timeout() function. This one can be called in a shutdown
function to tell you if you got there because of a timeout
- Add ignore_user_abort() function and .ini/.conf directive of same name
- Fix connection abort detection code - It should now work reliably with
Apache. Also added a user-level connection_aborted() function designed to
let people check whether the user aborted the connection in a user-level
shutdown function.
- Add pfsockopen() function
- Improvements in FreeType support: Macintosh fonts work, and non-antialiased
output is considerably cleaner <mka@satama.com>
- Fixed checkdate() function, range of valid years is now 0 to 32767
- hw_insertdocument() returns object id now
- Add pdf_open() warning in configure and documentation
- Add diskfreespace() function
- Added aspell support
- Iptcparse would sometimes find a wrong tag.
- Force var_dump() to output headers
- Add optional 3th parameter to ora_fetchinto.
- Serialize and var_dump no longer show array elements that
have been unset.
- Add IptcEmbed() function (can replace an APP13-Marker in a JPEG file)
- Add OCI8 module for Windows
- Fix bug in pdf_close() function
- Add WDDX support (see http://www.wddx.org for more info)
- Add similar_text() function
- Introduce simple regex compilation cache
-516
View File
@@ -1,516 +0,0 @@
List of PHP maintainers
=======================
Maintenance legend
------------------
Maintained: Someone actually looks after it.
Odd Fixes: It has a maintainer but they don't have time to do
much other than throw the odd patch in. See below.
Orphan: No current maintainer [but maybe you could take the
role as you write your new code].
Obsolete: Old code. Something tagged obsolete generally means
it has been replaced by a better system and you
should be using that.
Unknown: Not known at this time.
Status legend
-------------
Working: Working under both Windows and Unix.
Windows: Working only under Windows.
Unix: Working only under Unix.
Experimental: Under development or initial release.
Not Working: Not working.
Unknown: Status unknown.
== Server APIs ==
-------------------------------------------------------------------------------
EXTENSION: apache2handler
PRIMARY MAINTAINER: Aaron Bannert <aaron@php.net>, Ilia Alshanetsky <iliaa@php.net>
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: cgi
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: cli
PRIMARY MAINTAINER: Marcus Börger <helly@php.net>, Edin Kadribasic <edink@php.net>
MAINTENANCE: Xinchen Hui <laruence@php.net> (2013 - 2020)
STATUS: Working
SINCE: 4.3.0
-------------------------------------------------------------------------------
EXTENSION: embed
PRIMARY MAINTAINER: Edin Kadribasic <edink@php.net>
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: fpm
PRIMARY MAINTAINER: Jakub Zelenka <bukka@php.net>
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3.3
-------------------------------------------------------------------------------
EXTENSION: litespeed
PRIMARY MAINTAINER: George Wang <gwang@php.net>
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: phpdbg
PRIMARY MAINTAINER: Joe Watkins <krakjoe@php.net>, Bob Weinand <bwoebi@php.net>
MAINTENANCE: Unknown
STATUS: 5.6
-------------------------------------------------------------------------------
== Database extensions ==
-------------------------------------------------------------------------------
EXTENSION: dba
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2002 - 2007)
Christopher Jones <sixd@php.net> (2008 - 2013)
Pierre-Alain Joye <pajoye@php.net> (2011 - 2011)
MAINTENANCE: Maintained
STATUS: Working
COMMENT: DBM abstraction for db2, db3, db4, dbm, ndbm, gdbm, ini
-------------------------------------------------------------------------------
EXTENSION: mysqli
PRIMARY MAINTAINER: Georg Richter <georg@php.net> (2003 - 2006)
Andrey Hristov <andrey@php.net> (2003 - 2016)
Johannes Schlüter <johannes@php.net> (2008 - 2014)
Ulf Wendel <uw@php.net> (2007 - 2013)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: mysqlnd
PRIMARY MAINTAINER: Andrey Hristov <andrey@php.net> (2007 - 2017)
Johannes Schlüter <johannes@php.net> (2008 - 2018)
Ulf Wendel <uw@php.net> (2009 - 2011)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: oci8
PRIMARY MAINTAINER: Christopher Jones <sixd@php.net> (2007 - 2017)
Antony Dovgal <tony2001@php.net> (2003 - 2009)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: odbc
PRIMARY MAINTAINER: Daniel R. Kalowsky <kalowsky@php.net> (2000 - 2004)
MAINTENANCE: Maintained
STATUS: Working
COMMENT: Working
-------------------------------------------------------------------------------
EXTENSION: pdo
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2011)
Wez Furlong <wez@php.net> (2004 - 2006)
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_dblib
PRIMARY MAINTAINER: Adam Baratz <adambaratz@php.net> (2016 - 2017)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_firebird
PRIMARY MAINTAINER: Lars Westermann <lwe@php.net> (2007 - 2007)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_mysql
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2010)
Johannes Schlüter <johannes@php.net> (2008 - 2014)
Andrey Hristov <andrey@php.net> (2005 - 2015)
Ulf Wendel <uw@php.net> (2008 - 2012)
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_odbc
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_oci
PRIMARY MAINTAINER: Christopher Jones <sixd@php.net> (2007 - 2017)
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_pgsql
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2011)
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pdo_sqlite
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2005 - 2011)
MAINTENANCE: Odd fixes
STATUS: Working
SINCE: 5.1
-------------------------------------------------------------------------------
EXTENSION: pgsql
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2002 - 2007)
Yasuo Ohgaki <yohgaki@php.net> (2001 - 2015)
MAINTENANCE: Maintained
STATUS: Working
COMMENT: Use PostgreSQL 7.0.x or later. PostgreSQL 6.5.3 or less have fatal bug.
-------------------------------------------------------------------------------
EXTENSION: sqlite3
PRIMARY MAINTAINER: Scott MacVicar <scottmac@php.net> (2008 - 2011)
Christoph M. Becker <cmb@php.net> (2016 - 2020)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
COMMENT: Integrates SQLite 3 embeddable SQL database engine.
-------------------------------------------------------------------------------
== XML extensions ==
-------------------------------------------------------------------------------
EXTENSION: dom
PRIMARY MAINTAINER: Christian Stocker <chregu@php.net> (2003 - 2011)
Rob Richards <rrichards@php.net> (2003 - 2012)
Marcus Börger <helly@php.net> (2003 - 2006)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: simplexml
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2008)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: soap
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2004 - 2018)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xml
PRIMARY MAINTAINER: Thies C. Arntzen <thies@thieso.net> (1999 - 2002)
Rob Richards <rrichards@php.net> (2003 - 2013)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: libxml
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2003 - 2009)
Christian Stocker <chregu@php.net> (2004 - 2011)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xmlreader
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
Christian Stocker <chregu@php.net> (2004 - 2004)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xmlwriter
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
Pierre-Alain Joye <pajoye@php.net> (2005-2009)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xsl
PRIMARY MAINTAINER: Christian Stocker <chregu@php.net> (2003 - 2011)
Rob Richards <rrichards@php.net> (2003 - 2010)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
== Other extensions ==
-------------------------------------------------------------------------------
EXTENSION: bcmath
PRIMARY MAINTAINER: Andi Gutmans <andi@php.net> (2000 - 2004)
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: bz2
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2004 - 2004)
MAINTENANCE: Odd Fixes
STATUS: Working
SINCE: 4.0.3
-------------------------------------------------------------------------------
EXTENSION: calendar
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2000 - 2004)
MAINTENANCE: Odd Fixes
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: com_dotnet
PRIMARY MAINTAINER: Wez Furlong <wez@php.net> (2003 - 2005)
Christoph M. Becker <cmb@php.net> (2018 - 2020)
MAINTENANCE: Maintained
STATUS: Windows
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: ctype
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2000 - 2004)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: curl
PRIMARY MAINTAINER: Sterling Hughes <sterling@php.net> (2000 - 2004)
Ilia Alshanetsky <iliaa@php.net> (2002 - 2011)
Pierrick Charron <pierrick@php.net> (2010 - 2016)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.0.2
-------------------------------------------------------------------------------
EXTENSION: date
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2005 - 2018)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: enchant
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: exif
PRIMARY MAINTAINER: Kalle Sommer Nielsen <kalle@php.net> (2010 - 2018)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.2
-------------------------------------------------------------------------------
EXTENSION: ffi
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2018 - 2019)
MAINTENANCE: Maintained
STATUS: Experimental
SINCE: 7.4.0
-------------------------------------------------------------------------------
EXTENSION: fileinfo
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2004 - 2008)
Anatol Belski <ab@php.net> (2012 - 2020)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: filter
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2006 - 2006)
Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
Ilia Alshanetsky <iliaa@php.net> (2006 - 2011)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.2
-------------------------------------------------------------------------------
EXTENSION: ftp
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Odd fixes
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: gd
PRIMARY MAINTAINER: Pierre-Alain Joye <pajoye@php.net> (2002 - 2016)
Christoph M. Becker <cmb@php.net> (2015 - 2020)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: gettext
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: gmp
PRIMARY MAINTAINER: Stanislav Malyshev <stas@php.net> (2000 - 2019)
Antony Dovgal <tony2001@php.net> (2005 - 2010)
Nikita Popov <nikic@php.net> (2013 - 2020)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.0.4
-------------------------------------------------------------------------------
EXTENSION: hash
PRIMARY MAINTAINER: Sara Golemon <pollita@php.net> (2005 - 2017)
Mike Wallner <mike@php.net> (2005 - 2013)
Anatol Belski <ab@php.net> (2014 - 2018)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.1.2
-------------------------------------------------------------------------------
EXTENSION: iconv
PRIMARY MAINTAINER: Moriyoshi Koizumi <moriyoshi@php.net> (2002 - 2010)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: intl
PRIMARY MAINTAINER: Stanislav Malyshev <stas@php.net> (2008 - 2019)
Anatol Belski <ab@php.net> (2017 - 2018)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: imap
PRIMARY MAINTAINER: Chuck Hagenbuch <chuck@horde.org> (1999 - 2004)
Ilia Alshanetsky <iliaa@php.net> (2002 - 2010)
Pierre-Alain Joye <pajoye@php.net> (2008 - 2010)
Bishop Bettini <bishop@php.net> (2018 - 2019)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: json
PRIMARY MAINTAINER: Jakub Zelenka <bukka@php.net> (2014 - 2018)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.2
-------------------------------------------------------------------------------
EXTENSION: ldap
PRIMARY MAINTAINER: Stig Venaas <venaas@php.net> (2000 - 2002)
Douglas Goldstein <cardoe@php.net> (2007 - 2007)
Pierre-Alain Joye <pajoye@php.net> (2008 - 2010)
Côme Bernigaud <mcmic@php.net> (2015 - 2017)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: mbstring
PRIMARY MAINTAINER: Rui Hirokawa <hirokawa@php.net> (2001 - 2013)
Nikita Popov <nikic@php.net> (2017 - 2020)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: opcache
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2013 - 2018)
Xinchen Hui <laruence@php.net> (2013 - 2020)
Nikita Popov <nikic@php.net> (2016 - 2020)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.5.0
-------------------------------------------------------------------------------
EXTENSION: openssl
PRIMARY MAINTAINER: Wez Furlong <wez@php.net> (2001 - 2006)
Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
Jakub Zelenka <bukka@php.net> (2015 - 2019)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.0.4
-------------------------------------------------------------------------------
EXTENSION: pcntl
PRIMARY MAINTAINER: Arnaud Le Blanc <lbarnaud@php.net> (2008 - 2010)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: pcre
PRIMARY MAINTAINER: Andrei Zmievski <andrei@php.net> (1999 - 2006)
Nuno Lopes <nlopess@php.net> (2006 - 2009)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: phar
PRIMARY MAINTAINER: Greg Beaver <cellog@php.net> (2008 - 2009)
Marcus Börger <helly@php.net> (2008 - 2008)
Steph Fox <sfox@php.net> (2008 - 2008)
Bishop Bettini <bishop@php.net> (2018 - 2019)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.3
-------------------------------------------------------------------------------
EXTENSION: posix
PRIMARY MAINTAINER: Kristian Köhntopp <kris@koehntopp.de> (2000 - 2000)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: pspell
PRIMARY MAINTAINER: Vlad Krupin <phpdevel@echospace.com> (2000 - 2004)
MAINTENANCE: Unknown
STATUS: Working
SINCE: 4.0.2
-------------------------------------------------------------------------------
EXTENSION: readline
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: reflection
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2009)
Johannes Schlüter <johannes@php.net> (2006 - 2014)
Nikita Popov <nikic@php.net> (2019 - 2020)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: session
PRIMARY MAINTAINER: Sascha Schumann <sascha@schumann.cx> (1999 - 2004)
Ilia Alshanetsky <iliaa@php.net> (2002 - 2012)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: shmop
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2002 - 2008)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.0.3
-------------------------------------------------------------------------------
EXTENSION: snmp
PRIMARY MAINTAINER: Boris Lytochkin <lytboris@php.net> (2011 - 2013)
Rasmus Lerdorf <rasmus@php.net> (1999 - 2002)
Pierre-Alain Joye <pajoye@php.net> (2010 - 2011)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: sockets
PRIMARY MAINTAINER: Chris Vandomelen <chrisv@b0rked.dhs.org> (2000 - 2000)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 4.0.2
-------------------------------------------------------------------------------
EXTENSION: sodium
PRIMARY MAINTAINER: Frank Denis <jedisct1@php.net> (2017 - 2017)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 7.2.0
-------------------------------------------------------------------------------
EXTENSION: spl
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2009)
Etienne Kneuss <colder@php.net> (2008 - 2014)
MAINTENANCE: Maintained
STATUS: Working
SINCE: 5.0.0
-------------------------------------------------------------------------------
EXTENSION: sysvmsg
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: sysvsem
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: sysvshm
PRIMARY MAINTAINER: Unknown
MAINTENANCE: Unknown
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: tidy
PRIMARY MAINTAINER: John Coggeshall <john@php.net> (2003 - 2006)
Ilia Alshanetsky <iliaa@php.net> (2003 - 2009)
Nuno Lopes <nlopess@php.net> (2006 - 2012)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: tokenizer
PRIMARY MAINTAINER: Andrei Zmievski <andrei@php.net> (2002 - 2002)
Nikita Popov <nikic@php.net> (2013 - 2020)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: zip
PRIMARY MAINTAINER: Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
Remi Collet <remi@php.net> (2013-2020)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: zlib
PRIMARY MAINTAINER: Stefan Roehrich <sr@linux.de> (1999 - 2003)
MAINTENANCE: Maintained
STATUS: Working
-------------------------------------------------------------------------------
+538
View File
@@ -0,0 +1,538 @@
Functions:
Functions marked with 'u' do not work, or may not work correctly under windows.
basic_functions
include
_include
isset
intval
doubleval
strval
short_tags
sleep
u usleep
ksort
asort
sort
count
chr
ord
flush
end
prev
next
reset
current
key
gettype
settype
min
max
addslashes
chop
pos
fsockopen
getimagesize
htmlspecialchars
md5
parse_url
parse_str
phpinfo
phpversion
strlen
strtok
strtoupper
strtolower
strchr
basename
dirname
stripslashes
strstr
strrchr
substr
quotemeta
urlencode
urldecode
ucfirst
strtr
sprintf
printf
exec
system
escapeshellcmd
passthru
soundex
rand
srand
getrandmax
gethostbyaddr
gethostbyname
explode
implode
error_reporting
clearstatcache
get_current_user
getmyuid
getmypid
u getmyinode
getlastmod
base64_decode
base64_encode
abs
ceil
floor
sin
cos
tan
asin
acos
atan
pi
pow
exp
log
log10
sqrt
bindec
hexdec
octdec
decbin
decoct
dechex
getenv
putenv
time
mktime
date
gmdate
getdate
checkdate
microtime
uniqid
u linkinfo
u readlink
u symlink
u link
u unlink
bcmath_functions
bcadd
bcsub
bcmul
bcdiv
bcmod
bcpow
bcsqrt
bcscale
bccomp
dir_functions
opendir
closedir
chdir
rewinddir
readdir
dir
dl_functions
dl(string module_name); dynamicly load a module
dns_functions
gethostbyaddr
gethostbyname
file_functions
pclose
popen
readfile
rewind
rmdir
umask
fclose
feof
fgets
fgetss
fopen
fpassthru
fseek
ftell
fputs
mkdir
rename
copy
tempnam
file
filestat_functions
fileatime
filectime
u filegroup
u fileinode
filemtime
u fileowner
fileperms
filesize
filetype
stat
u chown
u chgrp
u chmod
touch
file_exists
is_executable
is_dir
is_readable
is_writeable
u is_link
header_functions
setcookie
header
mail_functions
mail
reg_functions
ereg
ereg_replace
eregi
eregi_replace
split
sql_regcase
syslog_functions (writes to event log on win NT)
openlog
syslog
closelog
The following are optional modules and may or may not be compiled into php, or may be compiled as a loadable module.
odbc_functions (obsolete, use uodbc below)
sqlconnect
sqldisconnect
sqlfetch
sqlexecdirect
sqlgetdata
sqlfree
sqlrowcount
uodbc_functions
(int) odbc_autocommit($connection_id, $OnOff)
(void) odbc_close($connection_id)
(void) odbc_close_all(void)
(int) odbc_commit($connection_id)
(int) odbc_connect($dsn, $user, $password)
(int) odbc_pconnect($dsn, $user, $password)
(string) odbc_cursor($result_id)
(int) odbc_do($connection_id, $query_string)
(int) odbc_exec($connection_id, $query_string)
(int) odbc_prepare($connection_id, $query_string)
(int) odbc_execute($result_id, $array)
(int) odbc_fetch_row($result_id, $row_number)
(int) odbc_fetch_into($result_id, $row_number, $array_ptr)
(int) odbc_field_len($result_id, $field_number)
(string) odbc_field_name($result_id, $field_number)
(string) odbc_field_type($result_id, $field)
(int) odbc_free_result($result_id)
(int) odbc_num_fields($result_id)
(int) odbc_num_rows($result_id)
(string) odbc_result($result_id, $field)
(int) odbc_result_all($result_id, $format)
(int) odbc_rollback($connection_id)
msql_functions
msql_connect
msql_pconnect
msql_close
msql_select_db
msql_create_db
msql_drop_db
msql_query
msql
msql_list_dbs
msql_list_tables
msql_list_fields
msql_result
msql_num_rows
msql_num_fields
msql_fetch_row
msql_fetch_array
msql_fetch_object
msql_data_seek
msql_fetch_field
msql_field_seek
msql_free_result
msql_fieldname
msql_fieldtable
msql_fieldlen
msql_fieldtype
msql_fieldflags
msql_regcase
/* for downwards compatability */
msql_selectdb
msql_createdb
msql_dropdb
msql_freeresult
msql_numfields
msql_numrows
msql_listdbs
msql_listtables
msql_listfields
msql_dbname
msql_tablename
ldap_functions
ldap_connect
ldap_bind
ldap_unbind
ldap_read
ldap_list
ldap_search
ldap_free_result
ldap_count_entries
ldap_first_entry
ldap_next_entry
ldap_get_entries
ldap_free_entry
ldap_first_attribute
ldap_next_attribute
ldap_get_attributes
ldap_get_values
ldap_get_dn
ldap_dn2ufn
ldap_add
ldap_delete
ldap_modify
gd_functions
imagearc
imagechar
imagecharup
imagecolorallocate
imagecolorclosest
imagecolorexact
imagecolortransparent
imagecopyresized
imagecreate
imagecreatefromgif
imagedestroy
imagefill
imagefilledpolygon
imagefilledrectangle
imagefilltoborder
imagegif
imageinterlace
imageline
imagepolygon
imagerectangle
imagesetpixel
imagestring
imagestringup
imagesx
imagesy
filepro_functions
filepro
filepro_rowcount
filepro_fieldname
filepro_fieldtype
filepro_fieldwidth
filepro_fieldcount
filepro_retrieve
dbm_functions
dblist
dbmopen
dbmclose
dbminsert
dbmfetch
dbmreplace
dbmexists
dbmdelete
dbmfirstkey
dbmnextkey
dbase_functions
dbase_open
dbase_create
dbase_close
dbase_numrecords
dbase_numfields
dbase_add_record
dbase_get_record
dbase_delete_record
dbase_pack
calendar_functions
jdtogregorian
gregoriantojd
jdtojulian
juliantojd
jdtojewish
jewishtojd
jdtofrench
frenchtojd
jddayofweek
jdmonthname
adabas_functions
(int) ada_afetch($result_id, $rownumber, $result array)
(int) ada_autocommit($connection_id, $OnOff)
(void) ada_close($connection_id)
ada_closeall
(int) ada_commit($connection_id)
(int) ada_connect($dsn, $user, $password)
(int) ada_exec($connection_id, $query_string)
(int) ada_fetchrow($result_id, $row?number)
ada_fieldlen
(string) ada_fieldname($result_id, $field_number)
(string) ada_fieldtype($result_id, $field)
(int) ada_freeresult($result_id)
(int) ada_numfields($result_id)
(int) ada_numrows($result_id)
(string) ada_result($result_id, $field)
(int) ada_resultall($result_id, $format)
(int) ada_rollback($connection_id)
***(int) ada_fieldnum($result_id, $field_name) (this function is not in adabase.c
crypt_functions
crypt
mysql_functions
mysql_connect
mysql_pconnect
mysql_close
mysql_select_db
mysql_create_db
mysql_drop_db
mysql_query
mysql
mysql_list_dbs
mysql_list_tables
mysql_list_fields
mysql_affected_rows
mysql_insert_id
mysql_result
mysql_num_rows
mysql_num_fields
mysql_fetch_row
mysql_fetch_array
mysql_fetch_object
mysql_data_seek
mysql_fetch_lengths
mysql_fetch_field
mysql_field_seek
mysql_free_result
mysql_fieldname
mysql_fieldtable
mysql_fieldlen
mysql_fieldtype
mysql_fieldflags
/* for downwards compatability */
mysql_selectdb
mysql_createdb
mysql_dropdb
mysql_freeresult
mysql_numfields
mysql_numrows
mysql_listdbs
mysql_listtables
mysql_listfields
mysql_dbname
mysql_tablename
oracle_functions
ora_close
ora_commit
ora_commitoff
ora_commiton
ora_error
ora_errorcode
ora_exec
ora_fetch
ora_getcolumn
ora_logoff
ora_logon
ora_open
ora_parse
ora_rollback
pgsql_functions
pg_connect
pg_pconnect
pg_close
pg_dbname
pg_errormessage
pg_options
pg_port
pg_tty
pg_host
pg_exec
pg_numrows
pg_numfields
pg_fieldname
pg_fieldsize
pg_fieldtype
pg_fieldnum
pg_result
pg_fieldprtlen
pg_getlastoid
pg_freeresult
pg_locreate
pg_lounlink
pg_loopen
pg_loclose
pg_loread
pg_lowrite
pg_loreadall
sybase_functions
sybase_connect
sybase_pconnect
sybase_close
sybase_select_db
sybase_query
sybase_free_result
sybase_get_last_message
sybase_num_rows
sybase_num_fields
sybase_fetch_row
sybase_fetch_array
sybase_fetch_object
sybase_data_seek
sybase_fetch_field
sybase_field_seek
sybase_result
sybase_old_functions
sybsql_seek
sybsql_exit
sybsql_dbuse
sybsql_query
sybsql_isrow
sybsql_result
sybsql_connect
sybsql_nextrow
sybsql_numrows
sybsql_getfield
sybsql_numfields
sybsql_fieldname
sybsql_result_all
sybsql_checkconnect
+186
View File
@@ -0,0 +1,186 @@
Installation Instructions for PHP 4.0
-------------------------------------
For the impatient here is a quick set of steps that will build PHP as
an Apache module for Apache 1.3.x with MySQL support. A more verbose
explanation follows.
QUICK INSTALL
$ gunzip -c apache_1.3.x.tar.gz | tar xf -
$ cd apache_1.3.x
$ ./configure
$ cd ..
$ gunzip -c php-4.0.x.tar.gz | tar xf -
$ cd php-4.0.x
$ ./configure --with-mysql --with-apache=../apache_1.3.x --enable-track-vars
$ make
$ make install
$ cd ../apache_1.3.x
$ ./configure --prefix=/www --activate-module=src/modules/php4/libphp4.a
(The above line is correct! Yes, we know libphp4.a does not exist at this
stage. It isn't supposed to. It will be created.)
make
(you should now have an httpd binary which you can copy to your Apache bin dir)
cd ../php-4.0.x
cp php.ini-dist /usr/local/lib/php.ini
You can edit /usr/local/lib/php.ini file to set PHP options.
Edit your httpd.conf or srm.conf file and add:
AddType application/x-httpd-php .php
VERBOSE INSTALL
Installing PHP can be done in four simple steps:
1. Unpack your distribution file.
You will have downloaded a file named something like php4xn.tar.gz.
Unzip this file with a command like: gunzip php4xn.tar.gz
Next you have to untar it with: tar -xvf php4xn.tar
This will create a php-4.0.x directory. cd into this new directory.
2. Configure PHP.
You now have to choose the options you would like. There are quite
a few of them. To see a list, type: ./configure --help
You can also use the supplied 'setup' script, which will ask you
a series of questions and automatically run the configure script
for you.
The only options that you are likely to want to use are the ones in
the last section entitled, "--enable and --with options recognized:"
A popular choice is to build the Apache module version. You need
to know where the source code directory for your Apache server is
located. Then use an option like: --with-apache=/usr/local/src/apache
if that is your Apache source code directory. If you only specify
--with-apache, then it will default to look for your Apache source
in /usr/local/etc/httpd.
NOTE: The directory you specify should be the top-level of the
unpacked Apache (or Stronghold) distribution. The configure program
will automatically look for httpd.h in different directories under that
location depending on which version of Apache, including Stronghold,
you are running.
For MySQL support, since newer versions of MySQL installs its various
components under /usr/local, this is the default. If you have
changed the location you can specify it with: --with-mysql=/opt/local
for example. Otherwise just use: --with-mysql
*NOTE* If you are using Apache 1.3b6 or later, you should run the
Apache Configure script at least once before compiling PHP. It
doesn't matter how you have Apache configured at this point.
3. Compile and install the files. Simply type: make install
For the Apache module version this will copy the appropriate files
to the src/modules/php4 directory in your Apache distribution if
you are using Apache 1.3.x. If you are still running Apache 1.2.x
these files will be copied directly to the main src directory.
For Apache 1.3b6 and later, you can use the new APACI configuration
mechanism. To automatically build Apache with PHP support, use:
cd apache_1.3.x
./configure --prefix=/<path>/apache \
--activate-module=src/modules/php4/libphp4.a
make
make install
If you do not wish to use this new configuration tool, the old
install procedure (src/Configure) will work fine.
If you are using the old Apache ./Configure script, you will have to
edit the Apache src/Configuration file manually. If you do not have
this file, copy Configuration.tmpl to Configuration.
For Apache 1.3.x add:
AddModule modules/php4/libphp4.a
For Apache 1.3.x don't do anything else. Just add this line and then
run "./Configure" followed by "make".
For Apache 1.2.x add:
Module php4_module mod_php4.o
For Apache 1.2.x you will also have to look in the libphp4.module file,
which was copied to the src directory. The EXTRA_LIBS line in the Apache
Configuration file needs to be set to use the same libs as specified on
the LIBS line in libphp4.module. You also need to make sure to add
"-L." to the beginning of the EXTRA_LIBS line.
So, as an example, your EXTRA_LIBS line might look like:
EXTRA_LIBS=-L. -lphp4 -lgdbm -ldb -L/usr/local/mysql/lib -lmysqlclient
NOTE: You should not enclose the EXTRA_LIBS line in double-quotes, as it
is in the libphp4.module file.
Also, look at the RULE_WANTHSREGEX setting in the libphp4.module file
and set the WANTHSREGEX directive accordingly in your Configuration file.
This last step applies to versions of Apache prior to 1.3b3.
This is a bit of a hassle, but should serve as incentive to move to
Apache 1.3.x where this step has been eliminated.
Once you are satisfied with your Configuration settings, type: ./Configure
If you get errors, chances are that you forgot a library or made a typo
somewhere. Re-edit Configuration and try again. If it goes well,
type: make
4. Setting up the server.
You should now have a new httpd binary. Shut down your existing server,
if you have one, and copy this new binary overtop of it. Perhaps make
a backup of your previous one first. Then edit your conf/srm.conf file
and add the line:
AddType application/x-httpd-php .php
There is also an interesting feature which can be quite instructive and
helpful while debugging. That is the option of having colour syntax
highlighting. To enable this, add the following line:
AddType application/x-httpd-php-source .phps
Any file ending in .phps will now be displayed with full colour syntax
highlighting instead of being executed.
When you are finished making changes to your srm.conf file, you can
start up your server.
USING PHP3 AND PHP4 AS CONCURRENT APACHE MODULES
Recent operating systems provide the ability to perform versioning and
scoping. This features make it possible to let PHP3 and PHP4 run as
concurrent modules in one Apache server.
This feature is known to work on the following platforms:
- Linux with recent binutils (binutils 2.9.1.0.25 tested)
- Solaris 2.5 or better
- FreeBSD (3.2, 4.0 tested)
To enable it, configure PHP3 and PHP4 to use APXS (--with-apxs) and the
necessary link extensions (--enable-versioning). Otherwise, all standard
installations instructions apply. For example:
$ ./configure \
--with-apxs=/apache/bin/apxs \
--enable-versioning \
--with-mysql \
--enable-track-vars
If this also works on your platform or if you know a way to do it, please
report it to our bug database at http://bugs.php.net
+41 -39
View File
@@ -1,68 +1,70 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2021 The PHP Group. All rights reserved.
--------------------------------------------------------------------
--------------------------------------------------------------------
The PHP License, version 2.01
Copyright (c) 1999 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior permission from the
PHP Group. This does not apply to add-on libraries or tools
that work in conjunction with PHP. In such a case the PHP
name may be used to indicate that the product supports PHP.
4. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
of the license, you may always continue to use it under the
terms of that version. You may also choose to use such covered
code under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
5. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
<http://www.php.net/software/>".
"This product includes PHP, freely available from
http://www.php.net/".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
6. Permission to freely distribute and use Zend as an integrated
part of PHP is granted, under the conditions of version 0.91
of the Zend License.
The license is bundled with the Zend engine, and is available
at http://www.zend.com/license/0_91.txt, or by contacting
license@zend.com.
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
--------------------------------------------------------------------
This software consists of voluntary contributions made by many
individuals on behalf of the PHP Group.
The PHP Group can be contacted via Email at group@php.net.
The PHP Group can be contacted via Email at php-group@php.net.
For more information on the PHP Group and the PHP project,
For more information on the PHP Group and the PHP project,
please see <http://www.php.net>.
PHP includes the Zend Engine, freely available at
<http://www.zend.com>.
+20
View File
@@ -0,0 +1,20 @@
Module Status
------ ------
MySQL Working
COM Working
WDDX Working
PCRE Working
DBA Working
mcrypt Working
mhash Working
dbase Working
aspell Working
imap Working
ldap Working
oci8 Working (but no blob-support yet)
oracle Working
iptc Working
informix Working
zlib Working
sysvshm Working
odbc Working (except for persistent connections)
+240
View File
@@ -0,0 +1,240 @@
# +----------------------------------------------------------------------+
# | PHP HTML Embedded Scripting Language Version 4.0 |
# +----------------------------------------------------------------------+
# | Copyright (c) 1997-1999 PHP Development Team (See Credits file) |
# +----------------------------------------------------------------------+
# | This program is free software; you can redistribute it and/or modify |
# | it under the terms of one of the following licenses: |
# | |
# | A) the GNU General Public License as published by the Free Software |
# | Foundation; either version 2 of the License, or (at your option) |
# | any later version. |
# | |
# | B) the PHP License as published by the PHP Development Team and |
# | included in the distribution in the file: LICENSE |
# | |
# | This program is distributed in the hope that it will be useful, |
# | but WITHOUT ANY WARRANTY; without even the implied warranty of |
# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
# | GNU General Public License for more details. |
# | |
# | You should have received a copy of both licenses referred to here. |
# | If you did not, or have any questions about PHP licensing, please |
# | contact core@php.net. |
# +----------------------------------------------------------------------+
#
# $Id$
#
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = @srcdir@
bindir = @bindir@
top_builddir = .
ZEND_DIR = $(srcdir)/libzend
TSRM_DIR = @TSRM_DIR@
SUBDIRS=libzend ext $(TSRM_DIR)
PACKAGE = @PACKAGE@
VERSION = @VERSION@
LN_S = @LN_S@
CC = @CC@
AR = ar rc
BINNAME = @BINNAME@
INSTALL_IT = @INSTALL_IT@
EXTRA_LIBS = @EXTRA_LIBS@
EXT_LIBS = @EXT_LIBS@
INCLUDES = @INCLUDES@
INCLUDE = -I$(srcdir) -I. -I$(ZEND_DIR) -I$(srcdir)/TSRM $(INCLUDES)
PROF_CFLAGS =
CFLAGS_SHLIB = @CFLAGS_SHLIB@
LDFLAGS_SHLIB = @LDFLAGS_SHLIB@
LDFLAGS_SHLIB_EXPORT = @LDFLAGS_SHLIB_EXPORT@
CPPFLAGS = @CPPFLAGS@
DEFS = @DEFS@
CFLAGS = @CFLAGS@ @DEBUG_CFLAGS@ $(PROF_CFLAGS)
COMPILE = $(CC) $(CFLAGS) $(CFLAGS_SHLIB) $(CPPFLAGS) $(INCLUDE) $(DEFS) @STRONGHOLD@
LDFLAGS = @VERSION_SCRIPT@ @RPATHS@ @LDFLAGS@ $(LDFLAGS_SHLIB) $(LDFLAGS_SHLIB_EXPORT) -L$(ZEND_DIR)
REGCFLAGS = $(CFLAGS)
RANLIB = @RANLIB@
YACC = @YACC@
MAINT = @MAINT@
APXS = @APXS@
APXS_LDFLAGS = $(EXTRA_LIBS) $(LIBS)
APXS_EXP = @APXS_EXP@
WARNING_LEVEL = @WARNING_LEVEL@
LEX_CFLAGS = -w$(WARNING_LEVEL) @LEX_CFLAGS@
EXT_SHARED = @EXT_SHARED@
LIBOBJS=@LIBOBJS@
SOURCE = main.c internal_functions.c snprintf.c php3_sprintf.c \
configuration-parser.c configuration-scanner.c request_info.c \
safe_mode.c fopen-wrappers.c php3_realpath.c alloca.c output.c \
php_ini.c SAPI.c cgi_main.c rfc1867.c dlist.c php_content_types.c \
aolserver.c
OBJS = $(SOURCE:.c=.o) $(LIBOBJS)
PHPLIBS = -Llibzend -lzend -Lext -lphpext
LIBS = $(PHPLIBS) $(EXTRA_LIBS) @LIBS@
all: $(BINNAME)
all-recursive clean-recursive distclean-recursive \
maintainer-clean-depend-recursive:
@set fnord $(MAKEFLAGS); amf=$$2; \
for subdir in $(SUBDIRS); do \
target=`echo $@ | sed s/-recursive//`; \
echo "Making $$target in $$subdir"; \
(cd $$subdir && $(MAKE) $$target) || fail=yes; \
done && test -z "$$fail"
# CGI binary or fhttpd module
php: all-recursive $(OBJS) @REGEX_LIB@ @FHTTPD_LIB@
$(CC) $(CFLAGS) -o $(BINNAME) $(LDFLAGS) $(OBJS) $(LIBS)
# Apache modules
libphp4.a libmodphp4.a: all-recursive $(OBJS) @REGEX_LIB@
$(AR) $@.tmp $(OBJS)
$(srcdir)/scripts/armerge $@ $@.tmp ext/libphpext.a libzend/libzend.a @TSRM_LIB@
@rm -f $@.tmp
$(RANLIB) $(BINNAME)
# Apache modules
libmodphp4-so.a: all-recursive $(OBJS) @REGEX_LIB@
$(AR) $@.tmp $(OBJS)
$(srcdir)/scripts/armerge $@ $@.tmp ext/libphpext.a libzend/libzend.a @TSRM_LIB@
@rm -f $@.tmp
$(RANLIB) libmodphp4-so.a
# Apache 1.3 shared module
libphp4.so: $(srcdir)/mod_php4.c libmodphp4-so.a @REGEX_LIB@
-@test -f ./mod_php4.c || test -L ./mod_php4.c || $(LN_S) $(srcdir)/mod_php4.c ./mod_php4.c
-@test -f ./mod_php4.c || test -h ./mod_php4.c || $(LN_S) $(srcdir)/mod_php4.c ./mod_php4.c
$(APXS) $(INCLUDE) -c -o libphp4.so @VERSION_SCRIPT@ @RPATHS@ ./mod_php4.c libmodphp4-so.a $(APXS_LDFLAGS) $(APXS_EXP)
php4_aol.so: libmodphp4-so.a
g++ $(LDFLAGS) -shared aolserver.o -o $@ libmodphp4-so.a $(LIBS)
regex/libregex.a:
(cd regex; $(MAKE) lib)
configuration-parser.h configuration-parser.c: $(srcdir)/configuration-parser.y
bison -p cfg -v -d $(srcdir)/configuration-parser.y -o configuration-parser.c
configuration-scanner.o: configuration-scanner.c
$(COMPILE) $(LEX_CFLAGS) -c configuration-scanner.c
configuration-scanner.c: $(srcdir)/configuration-scanner.l
flex -Pcfg -oconfiguration-scanner.c -i $(srcdir)/configuration-scanner.l
clean: clean-recursive
-rm -f libphp4.a libmodphp4.a libphp4.so php *.o
-rm -f test/php.desc test/php.in test/php.out test/php.test
-rm -f test/a.tmp test/b.tmp test/test.dbm*
distclean: clean distclean-recursive
-rm -f *-parser.[ch] *-scanner.c *.output
-rm -f config.status config.cache config.log
-rm -f Makefile Makefile.depend php_config.h build-defs.h
-rm -f libphp4.module stamp-h buildconf.stamp
-rm -f regex/*.o regex/*.a regex/*.ih
-rm -f doc/checkdoc doc/funcparse doc/version.ent
-rm -f do-conf test/test.log
-rm -f doc/Makefile regex/Makefile
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
dist: distdir
-chmod -R a+r $(distdir)
tar chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
distdir:
-rm -rf $(distdir)
files=`echo *` ;\
mkdir $(distdir) ;\
for file in $$files ; do \
d=$(srcdir); \
if test -d $$d/$$file ; then \
cp -pr $$d/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
(cd $(distdir) ; $(MAKE) distclean)
cd $(distdir)/libzend ;\
flex -Pzend -ozend-scanner.c -i zend-scanner.l ;\
bison -p zend -v -d zend-parser.y -o zend-parser.c
cd $(distdir) ;\
flex -Pcfg -oconfiguration-scanner.c -i configuration-scanner.l ;\
bison -p cfg -v -d configuration-parser.y -o configuration-parser.c
find $(distdir) -name CVS -o -name .cvsignore | xargs rm -rf
maintainer-clean-depend: maintainer-clean-depend-recursive
bench: $(BINNAME)
./$(BINNAME) -c. tests/bench.phtml
# can't use a single rule for this because 'test' is a directory
test: regression
regression check: $(BINNAME)
cd test && ./testall
config.status: configure
./config.status --recheck
build-defs.h php_config.h: stamp-h
stamp-h: php_config.h.in config.status
CONFIG_FILES='build-defs.h stamp-h' ./config.status
Makefile: Makefile.in config.status
CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
#
# You must use '--enable-maintainer-mode' with configure to enable
# these rules, which requires autoconf be installed.
#
configure: @MAINT@ configure.in aclocal.m4
cd $(srcdir) && autoconf
php_config.h.in: @MAINT@ stamp-h.in
stamp-h.in: configure.in aclocal.m4 acconfig.h
cd ${srcdir} && autoheader && touch ${srcdir}/stamp-h.in
install: install-recursive $(BINNAME)
$(INSTALL_IT)
install-recursive:
if test "$(EXT_SHARED)" != ""; then \
for dir in X $(EXT_SHARED); do \
test -d ext/$$dir && (cd ext/$$dir; $(MAKE) install); \
done; \
fi
indent: clean
indent -v -kr -cli4 -ts4 \
-T pval -T HashTable -T Bucket -T Token -T TokenCache -T TokenCacheManager \
-T switch_expr -T internal_function -T control_structure_data \
-T MemoryHashTable -T MemoryBucket \
-T pvalue_value -T Stack *.c *.h
rm -f *~
.c.o:
$(COMPILE) -c $<
parser-scanner: configuration-parser.c configuration-scanner.c
depend: parser-scanner
$(CC) $(CFLAGS) -MM $(SOURCE) | perl -pe 's|regex/regex.h||;' > Makefile.depend
$(CC) $(CFLAGS) -MM $(FUNCTIONS_SOURCE) | perl -pe 's|^(.+\.o)|functions/$$1|; s|regex/regex.h||;' >> Makefile.depend
# Local Variables:
# tab-width: 4
# End:
-139
View File
@@ -1,139 +0,0 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.1.0alpha1
- Core:
. Fixed inclusion order for phpize builds on Windows. (cmb)
. Added missing hashtable insertion APIs for arr/obj/ref. (Sara)
. Fixed bug #75474 (function scope static variables are not bound to a unique
function). (Nikita)
. Fixed bug #53826 (__callStatic fired in base class through a parent call if
the method is private). (Nikita)
. Implemented FR #77372 (Relative file path is removed from uploaded file).
(Björn Tantau)
. Fixed bug #81076 (incorrect debug info on Closures with implicit binds).
(krakjoe)
- Standard:
. Fixed bug #77627 (method_exists on Closure::__invoke inconsistency).
(krakjoe)
- Date:
. Fixed bug #52480 (Incorrect difference using DateInterval) (Derick)
. Fixed bug #62326 (date_diff() function returns false result) (Derick)
. Fixed bug #64992 (dst not handled past 2038) (Derick)
. Fixed bug #65003 (Wrong date diff) (Derick)
. Fixed bug #66545 (DateTime. diff returns negative values) (Derick)
. Fixed bug #68503 (date_diff on two dates with timezone set localised
returns wrong results) (Derick)
. Fixed bug #69806 (Incorrect date from timestamp) (Derick)
. Fixed bug #71700 (Extra day on diff between begin and end of march 2016)
(Derick)
. Fixed bug #71826 (DateTime::diff confuse on timezone 'Asia/Tokyo') (Derick)
. Fixed bug #73460 (Datetime add not realising it already applied DST
change) (Derick)
. Fixed bug #74173 (DateTimeImmutable::getTimestamp() triggers DST switch in
incorrect time) (Derick)
. Fixed bug #74274 (Handling DST transitions correctly) (Derick)
. Fixed bug #74524 (Date diff is bad calculated, in same time zone) (Derick)
. Fixed bug #75167 (DateTime::add does only care about backward DST
transition, not forward) (Derick)
. Fixed bug #76032 (DateTime->diff having issues with leap days for
timezones ahead of UTC) (Derick)
. Fixed bug #76374 (Date difference varies according day time) (Derick)
. Fixed bug #77571 (DateTime's diff DateInterval incorrect in timezones from
UTC+01:00 to UTC+12:00 (Derick)
. Fixed bug #78452 (diff makes wrong in hour for Asia/Tehran) (Derick)
. Fixed bug #79452 (DateTime::diff() generates months differently between
time zones) (Derick)
. Fixed bug #79698 (timelib mishandles future timestamps (triggered by 'zic
-b slim')) (Derick)
. Fixed bug #79716 (Invalid date time created (with day "00")) (Derick)
. Fixed bug #80610 (DateTime calculate wrong with DateInterval) (Derick)
. Fixed bug #80664 (DateTime objects behave incorrectly around DST
transition) (Derick)
. Fixed bug #80913 (DateTime(Immutable)::sub around DST yield incorrect
time) (Derick)
- FPM:
. Added openmetrics status format. (Cees-Jan Kiewiet)
. Enable process renaming on macOS. (devnexen)
. Added pm.max_spawn_rate option to configure max spawn child processes rate.
(Paulius Sapragonas)
. Fixed bug #65800 (Events port mechanism). (psumbera)
- FTP:
. Convert resource<ftp> to object \FTP\Connection. (Sara)
- GD:
. Convert resource<gd font> to object \GdFont. (Sara)
- hash:
. Implemented FR #68109 (Add MurmurHash V3). (Anatol, Michael)
. Implemented FR #73385 (Add xxHash support). (Anatol)
- LDAP:
. Convert resource<ldap link> to object \LDAP\Connection. (Máté)
. Convert resource<ldap result> to object \LDAP\Result. (Máté)
. Convert resource<ldap result entry> to object \LDAP\ResultEntry. (Máté)
- MySQLi:
. Fixed bug #70372 (Emulate mysqli_fetch_all() for libmysqlclient). (Nikita)
. Fixed bug #80330 (Replace language in APIs and source code/docs).
(Darek Ślusarczyk)
. Fixed bug #80329 (Add option to specify LOAD DATA LOCAL white list folder
(including libmysql)). (Darek Ślusarczyk)
- MySQLnd:
. Fixed bug #80761 (PDO uses too much memory). (Nikita)
- OPcache:
. Added inheritance cache. (Dmitry)
- OpenSSL:
. Bump minimal OpenSSL version to 1.0.2. (Jakub Zelenka)
- PCRE:
. Bundled PCRE2 is 10.37.
- PDO:
. Fixed bug #40913 (PDO_MYSQL: PDO::PARAM_LOB does not bind to a stream for
fetching a BLOB). (Nikita)
. PDO MySQL:
. Fixed bug #80908 (PDO::lastInsertId() return wrong). (matt)
. Fixed bug #81037 (PDO discards error message text from prepared
statement). (Kamil Tekiela)
. PDO ODBC:
. Implement PDO_ATTR_SERVER_VERSION and PDO_ATTR_SERVER_INFO for
PDO::getAttribute(). (Calvin Buckley)
. PDO SQLite:
. Fixed bug #38334 (Proper data-type support for PDO_SQLITE). (Nikita)
- PgSQL:
. Convert resource<pgsql link> to object \PgSql\Connection. (Máté)
. Convert resource<pgsql result> to object \PgSql\Result. (Máté)
. Convert resource<pgsql large object> to object \PgSql\Lob. (Máté)
- PSpell:
. Convert resource<pspell> to object \PSpell\Dictionary. (Sara)
. Convert resource<pspell config> to object \PSpell\Config. (Sara)
- readline:
. Fixed bug #72998 (invalid read in readline completion). (krakjoe)
- Reflection:
. Implement ReflectionFunctionAbstract::getClosureUsedVariables (krakjoe)
- Sodium:
. Added the XChaCha20 stream cipher functions. (P.I.E. Security Team)
. Added the Ristretto255 functions, which are available in libsodium 1.0.18.
(P.I.E. Security Team)
- SPL:
. Fixed bug #80724 (FilesystemIterator::FOLLOW_SYMLINKS remove KEY_AS_FILE
from bitmask). (Cameron Porter)
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
+17
View File
@@ -0,0 +1,17 @@
How to install PHP with the BCMath arbitrary precision math library?
--------------------------------------------------------------------
Due to license restrictions, the BC math library can no longer be distributed
along with PHP. The BC math library is distributed under the restrictive
GNU Public License, and PHP is no longer distributed under that license, but
under a less restrictive license, the PHP License.
If you want to enable BC math support (recommended), all you have to do is
simply download http://www.php.net/extra/number4.tar.gz, and untar it on the
top level php4 directory.
A typical way of doing this would be (assuming that you have lynx):
cd ~/php4
lynx -dump -source http://www.php.net/extra/number4.tar.gz | gzip -d | tar xvf -
The PHP Group
+57
View File
@@ -0,0 +1,57 @@
QNX4 Installation Notes
-----------------------
NOTE: General installation instructions are in the INSTALL file
1. To compile and test PHP3 you have to grab, compile and install:
- GNU dbm library or another db library;
- GNU bison (1.25 or later; 1.25 tested);
- GNU flex (any version supporting -o and -P options; 2.5.4 tested);
- GNU diffutils (any version supporting -w option; 2.7 tested);
2. To use CVS version you may need also:
- GNU CVS (1.9 tested);
- GNU autoconf (2.12 tested);
- GNU m4 (1.3 or later preferable; 1.4 tested);
3. To run configure define -lunix in command line:
LDFLAGS=-lunix ./configure
4. To use Sybase SQL Anywhere define ODBC_QNX and CUSTOM_ODBC_LIBS in
command line and run configure with --with-custom-odbc:
CFLAGS=-DODBC_QNX LDFLAGS=-lunix CUSTOM_ODBC_LIBS="-ldblib -lodbc" ./configure --with-custom-odbc=/usr/lib/sqlany50
If you have SQL Anywhere version 5.5.00, then you have to add
CFLAGS=-DSQLANY_BUG
to workaround its SQLFreeEnv() bug. Other versions has not been tested,
so try without this flag first.
5. To build the Apache module, you may have to hardcode an include path for
alloc.h in your Apache base directory:
- APACHE_DIRECTORY/src/httpd.h:
change #include "alloc.h"
to #include "APACHE_DIRECTORY/src/alloc.h"
Unless you want to use system regex library, you have to hardcode also
a path to regex.h:
- APACHE_DIRECTORY/src/conf.h:
change #include <regex.h>
to #include "APACHE_DIRECTORY/src/regex/regex.h"
I don't know so far why this required for QNX, may be it is Watcom
compiler problem.
If you building Apache module with SQL Anywhere support, you'll get
symbol conflict with BOOL. It is defined in Apache (httpd.h) and in
SQL Anywhere (odbc.h). This has nothing to do with PHP, so you have to
fix it yourself someway.
6. With above precautions, it should compile as is and pass regression
tests completely:
make
make check
make install
Don't bother me unless you really sure you made that all but it
still doesn't work.
June 28, 1998
Igor Kovalenko -- owl@infomarket.ru
-642
View File
@@ -1,642 +0,0 @@
1. libmagic (ext/fileinfo) see ext/fileinfo/libmagic/LICENSE
2. libmbfl (ext/mbstring) see ext/mbstring/libmbfl/LICENSE
3. pcre2lib (ext/pcre)
4. ext/standard crypt
5. ext/standard crypt's blowfish implementation
6. ext/standard/rand
7. ext/standard/scanf
8. ext/standard/strnatcmp.c
9. ext/standard/uuencode
10. main/snprintf.c
11. main/strlcat
12. main/strlcpy
13. libgd (ext/gd)
14. ext/phar portions of tar implementations
15. ext/phar/zip.c portion extracted from libzip
16. libbcmath (ext/bcmath) see ext/bcmath/libbcmath/LICENSE
17. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
3. pcre2lib (ext/pcre)
PCRE2 LICENCE
-------------
PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD"
licence, as specified below, with one exemption for certain binary
redistributions. The documentation for PCRE2, supplied in the "doc" directory,
is distributed under the same terms as the software itself. The data in the
testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
included in the distribution is a just-in-time compiler that can be used to
optimize pattern matching. This is an optional feature that can be omitted when
the library is built.
THE BASIC LIBRARY FUNCTIONS
---------------------------
Written by: Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2019 University of Cambridge
All rights reserved.
PCRE2 JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
Copyright(c) 2010-2019 Zoltan Herczeg
All rights reserved.
STACK-LESS JUST-IN-TIME COMPILER
--------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
Copyright(c) 2009-2019 Zoltan Herczeg
All rights reserved.
THE "BSD" LICENCE
-----------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notices,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notices, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of any
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES
------------------------------------------
The second condition in the BSD licence (covering binary redistributions) does
not apply all the way down a chain of software. If binary package A includes
PCRE2, it must respect the condition, but if package B is software that
includes package A, the condition is not imposed on package B unless it uses
PCRE2 independently.
End
4. ext/standard crypt
FreeSec: libcrypt for NetBSD
Copyright (c) 1994 David Burren
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the author nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
5. ext/standard crypt's blowfish implementation
The crypt_blowfish homepage is:
http://www.openwall.com/crypt/
This code comes from John the Ripper password cracker, with reentrant
and crypt(3) interfaces added, but optimizations specific to password
cracking removed.
Written by Solar Designer <solar at openwall.com> in 1998-2011.
No copyright is claimed, and the software is hereby placed in the public
domain. In case this attempt to disclaim copyright and place the software
in the public domain is deemed null and void, then the software is
Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
general public under the following terms:
Redistribution and use in source and binary forms, with or without
modification, are permitted.
There's ABSOLUTELY NO WARRANTY, express or implied.
It is my intent that you should be able to use this on your system,
as part of a software package, or anywhere else to improve security,
ensure compatibility, or for any other purpose. I would appreciate
it if you give credit where it is due and keep your modifications in
the public domain as well, but I don't require that in order to let
you place this code and any modifications you make under a license
of your choice.
This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
"$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
ideas. The password hashing algorithm was designed by David Mazieres
<dm at lcs.mit.edu>. For more information on the level of compatibility,
please refer to the comments in BF_set_key() and to the crypt(3) man page
included in the crypt_blowfish tarball.
There's a paper on the algorithm that explains its design decisions:
http://www.usenix.org/events/usenix99/provos.html
Some of the tricks in BF_ROUND might be inspired by Eric Young's
Blowfish library (I can't be sure if I would think of something if I
hadn't seen his code).
6. ext/standard/rand
The following php_mt_...() functions are based on a C++ class MTRand by
Richard J. Wagner. For more information see the web page at
http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html
Mersenne Twister random number generator -- a C++ class MTRand
Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
The Mersenne Twister is an algorithm for generating random numbers. It
was designed with consideration of the flaws in various other generators.
The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
are far greater. The generator is also fast; it avoids multiplication and
division, and it benefits from caches and pipelines. For more information
see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
Reference
M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
Copyright (C) 2000 - 2003, Richard J. Wagner
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7. ext/standard/scanf
scanf.c --
This file contains the base code which implements sscanf and by extension
fscanf. Original code is from TCL8.3.0 and bears the following copyright:
This software is copyrighted by the Regents of the University of
California, Sun Microsystems, Inc., Scriptics Corporation,
and other parties. The following terms apply to all files associated
with the software unless explicitly disclaimed in individual files.
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
GOVERNMENT USE: If you are acquiring this software on behalf of the
U.S. government, the Government shall have only "Restricted Rights"
in the software and related documentation as defined in the Federal
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
are acquiring the software on behalf of the Department of Defense, the
software shall be classified as "Commercial Computer Software" and the
Government shall have only "Restricted Rights" as defined in Clause
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
authors grant the U.S. Government and others acting in its behalf
permission to use and distribute the software in accordance with the
terms specified in this license.
8. ext/standard/strnatcmp.c
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
9. ext/standard/uuencode
Portions of this code are based on Berkeley's uuencode/uudecode
implementation.
Copyright (c) 1983, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
10. main/snprintf.c
Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Sponsored in part by the Defense Advanced Research Projects
Agency (DARPA) and Air Force Research Laboratory, Air Force
Materiel Command, USAF, under agreement number F39502-99-1-0512.
main/spprintf
Copyright (c) 1995-1998 The Apache Group. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. All advertising materials mentioning features or use of this
software must display the following acknowledgment:
"This product includes software developed by the Apache Group
for use in the Apache HTTP server project (http://www.apache.org/)."
4. The names "Apache Server" and "Apache Group" must not be used to
endorse or promote products derived from this software without
prior written permission.
5. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes software developed by the Apache Group
for use in the Apache HTTP server project (http://www.apache.org/)."
THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================
This software consists of voluntary contributions made by many
individuals on behalf of the Apache Group and was originally based
on public domain software written at the National Center for
Supercomputing Applications, University of Illinois, Urbana-Champaign.
For more information on the Apache Group and the Apache HTTP server
project, please see <http://www.apache.org/>.
This code is based on, and used with the permission of, the
SIO stdio-replacement strx_* functions by Panos Tsirigotis
<panos@alumni.cs.colorado.edu> for xinetd.
11. main/strlcat
12. main/strlcpy
Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13. libgd (ext/gd)
* Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004 by Cold Spring Harbor Laboratory. Funded under
Grant P41-RR02188 by the National Institutes of Health.
* Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004 by Boutell.Com, Inc.
* Portions relating to GD2 format copyright 1999, 2000, 2001, 2002,
2003, 2004 Philip Warner.
* Portions relating to PNG copyright 1999, 2000, 2001, 2002, 2003,
2004 Greg Roelofs.
* Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002,
2003, 2004 John Ellson (ellson@graphviz.org).
* Portions relating to gdft.c copyright 2001, 2002, 2003, 2004 John
Ellson (ellson@graphviz.org).
* Portions copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Pierre-Alain Joye (pierre@libgd.org).
* Portions relating to JPEG and to color quantization copyright
2000, 2001, 2002, 2003, 2004, Doug Becker and copyright (C) 1994,
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Thomas
G. Lane. This software is based in part on the work of the
Independent JPEG Group. See the file README-JPEG.TXT for more
information.
* Portions relating to GIF compression copyright 1989 by Jef
Poskanzer and David Rowley, with modifications for thread safety
by Thomas Boutell.
* Portions relating to GIF decompression copyright 1990, 1991, 1993
by David Koblas, with modifications for thread safety by Thomas
Boutell.
* Portions relating to WBMP copyright 2000, 2001, 2002, 2003, 2004
Maurice Szmurlo and Johan Van den Brande.
* Portions relating to GIF animations copyright 2004 Jaakko Hyvätti
(jaakko.hyvatti@iki.fi)
Permission has been granted to copy, distribute and modify gd in
any context without fee, including a commercial application,
provided that this notice is present in user-accessible supporting
documentation.
This does not affect your ownership of the derived work itself,
and the intent is to assure proper credit for the authors of gd,
not to interfere with your productive use of gd. If you have
questions, ask. "Derived works" includes all programs that utilize
the library. Credit must be given in user-accessible
documentation.
This software is provided "AS IS." The copyright holders disclaim
all warranties, either express or implied, including but not
limited to implied warranties of merchantability and fitness for a
particular purpose, with respect to this code and accompanying
documentation.
Although their code does not appear in the current release, the
authors wish to thank David Koblas, David Rowley, and Hutchison
Avenue Software Corporation for their prior contributions.
END OF COPYRIGHT STATEMENT
14. ext/phar portions of tar implementations
portions of tar implementations in ext/phar - phar_tar_octal() are based on an
implementation by Tim Kientzle from libarchive, licensed with this license:
Copyright (c) 2003-2007 Tim Kientzle
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15. ext/phar/zip.c portion extracted from libzip
zip_dirent.c -- read directory entry (local or central), clean dirent
Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
This function is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <nih@giga.or.at>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The names of the authors may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
The OpenLDAP Public License
Version 2.8, 17 August 2003
Redistribution and use of this software and associated documentation
("Software"), with or without modification, are permitted provided
that the following conditions are met:
1. Redistributions in source form must retain copyright statements
and notices,
2. Redistributions in binary form must reproduce applicable copyright
statements and notices, this list of conditions, and the following
disclaimer in the documentation and/or other materials provided
with the distribution, and
3. Redistributions must contain a verbatim copy of this document.
The OpenLDAP Foundation may revise this license from time to time.
Each revision is distinguished by a version number. You may use
this Software under terms of this license revision or under the
terms of any subsequent revision of the license.
THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The names of the authors and copyright holders must not be used in
advertising or otherwise to promote the sale, use or other dealing
in this Software without specific, written prior permission. Title
to copyright in this Software shall at all times remain with copyright
holders.
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
California, USA. All Rights Reserved. Permission to copy and
distribute verbatim copies of this document is granted.
-144
View File
@@ -1,144 +0,0 @@
<div align="center">
<a href="https://php.net">
<img
alt="PHP"
src="https://www.php.net/images/logos/new-php-logo.svg"
width="150">
</a>
</div>
# The PHP Interpreter
PHP is a popular general-purpose scripting language that is especially suited to
web development. Fast, flexible and pragmatic, PHP powers everything from your
blog to the most popular websites in the world. PHP is distributed under the
[PHP License v3.01](LICENSE).
[![Build status](https://travis-ci.org/php/php-src.svg?branch=master)](https://travis-ci.org/php/php-src)
[![Build status](https://ci.appveyor.com/api/projects/status/meyur6fviaxgdwdy/branch/master?svg=true)](https://ci.appveyor.com/project/php/php-src)
[![Build Status](https://dev.azure.com/phpazuredevops/php/_apis/build/status/php.php-src?branchName=master)](https://dev.azure.com/phpazuredevops/php/_build/latest?definitionId=1&branchName=master)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/php.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:php)
## Documentation
The PHP manual is available at [php.net/docs](https://php.net/docs).
## Installation
### Prebuilt packages and binaries
Prebuilt packages and binaries can be used to get up and running fast with PHP.
For Windows, the PHP binaries can be obtained from
[windows.php.net](https://windows.php.net). After extracting the archive the
`*.exe` files are ready to use.
For other systems, see the [installation chapter](https://php.net/install).
### Building PHP source code
*For Windows, see [Build your own PHP on Windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).*
For a minimal PHP build from Git, you will need autoconf, bison, and re2c. For
a default build, you will additionally need libxml2 and libsqlite3.
On Ubuntu, you can install these using:
sudo apt install -y pkg-config build-essential autoconf bison re2c \
libxml2-dev libsqlite3-dev
On Fedora, you can install these using:
sudo dnf install re2c bison autoconf make libtool ccache libxml2-devel sqlite-devel
Generate configure:
./buildconf
Configure your build. `--enable-debug` is recommended for development, see
`./configure --help` for a full list of options.
# For development
./configure --enable-debug
# For production
./configure
Build PHP. To speed up the build, specify the maximum number of jobs using `-j`:
make -j4
The number of jobs should usually match the number of available cores, which
can be determined using `nproc`.
## Testing PHP source code
PHP ships with an extensive test suite, the command `make test` is used after
successful compilation of the sources to run this test suite.
It is possible to run tests using multiple cores by setting `-jN` in
`TEST_PHP_ARGS`:
make TEST_PHP_ARGS=-j4 test
Shall run `make test` with a maximum of 4 concurrent jobs: Generally the maximum
number of jobs should not exceed the number of cores available.
The [qa.php.net](https://qa.php.net) site provides more detailed info about
testing and quality assurance.
## Installing PHP built from source
After a successful build (and test), PHP may be installed with:
make install
Depending on your permissions and prefix, `make install` may need super user
permissions.
## PHP extensions
Extensions provide additional functionality on top of PHP. PHP consists of many
essential bundled extensions. Additional extensions can be found in the PHP
Extension Community Library - [PECL](https://pecl.php.net).
## Contributing
Contributions are most welcome by forking the
[GitHub repository](https://github.com/php/php-src) and sending a pull request.
Discussions are done on GitHub, but depending on the topic can also be relayed
to the official PHP developer mailing list internals@lists.php.net.
New features require an RFC and must be accepted by the developers. See
[Request for comments - RFC](https://wiki.php.net/rfc) and
[Voting on PHP features](https://wiki.php.net/rfc/voting) for more information
on the process.
Bug fixes **do not** require an RFC but require a bug tracker ticket. Open a
ticket at [bugs.php.net](https://bugs.php.net) and reference the bug id using
`#NNNNNN`.
Fix #55371: get_magic_quotes_gpc() throws deprecation warning
After removing magic quotes, the get_magic_quotes_gpc function caused a
deprecated warning. get_magic_quotes_gpc can be used to detect the
magic_quotes behavior and therefore should not raise a warning at any time.
The patch removes this warning.
See [Git workflow](https://wiki.php.net/vcs/gitworkflow) for more details on the
pull request workflow.
### Guidelines for contributors
See further documents in the repository for more information on how to
contribute:
- [Contributing to PHP](/CONTRIBUTING.md)
- [PHP coding standards](/CODING_STANDARDS.md)
- [Mailinglist rules](/docs/mailinglist-rules.md)
- [PHP release process](/docs/release-process.md)
## Credits
For the list of people who've put work into PHP, please see the
[PHP credits page](https://php.net/credits.php).
-26
View File
@@ -1,26 +0,0 @@
Copyright (c) 1999-2006, Andi Gutmans, Sascha Schumann, Zeev Suraski.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Neither name of the copyright holders nor the names of their contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-783
View File
@@ -1,783 +0,0 @@
/*
+----------------------------------------------------------------------+
| Thread Safe Resource Manager |
+----------------------------------------------------------------------+
| Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
| This source file is subject to the TSRM license, that is bundled |
| with this package in the file LICENSE |
+----------------------------------------------------------------------+
| Authors: Zeev Suraski <zeev@php.net> |
+----------------------------------------------------------------------+
*/
#include "TSRM.h"
#ifdef ZTS
#include <stdio.h>
#include <stdarg.h>
#if ZEND_DEBUG
# include <assert.h>
# define TSRM_ASSERT(c) assert(c)
#else
# define TSRM_ASSERT(c)
#endif
typedef struct _tsrm_tls_entry tsrm_tls_entry;
/* TSRMLS_CACHE_DEFINE; is already done in Zend, this is being always compiled statically. */
TSRMLS_CACHE_EXTERN();
struct _tsrm_tls_entry {
void **storage;
int count;
THREAD_T thread_id;
tsrm_tls_entry *next;
};
typedef struct {
size_t size;
ts_allocate_ctor ctor;
ts_allocate_dtor dtor;
size_t fast_offset;
int done;
} tsrm_resource_type;
/* The memory manager table */
static tsrm_tls_entry **tsrm_tls_table=NULL;
static int tsrm_tls_table_size;
static ts_rsrc_id id_count;
/* The resource sizes table */
static tsrm_resource_type *resource_types_table=NULL;
static int resource_types_table_size;
/* Reserved space for fast globals access */
static size_t tsrm_reserved_pos = 0;
static size_t tsrm_reserved_size = 0;
static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
/* New thread handlers */
static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
static tsrm_thread_end_func_t tsrm_new_thread_end_handler = NULL;
static tsrm_shutdown_func_t tsrm_shutdown_handler = NULL;
/* Debug support */
int tsrm_error(int level, const char *format, ...);
/* Read a resource from a thread's resource storage */
static int tsrm_error_level;
static FILE *tsrm_error_file;
#ifdef TSRM_DEBUG
#define TSRM_ERROR(args) tsrm_error args
#define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
{ \
int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset); \
\
if (offset==0) { \
return &array; \
} else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) { \
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X", \
unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset])); \
return array[unshuffled_offset]; \
} else { \
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", \
unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1))); \
return NULL; \
} \
}
#else
#define TSRM_ERROR(args)
#define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
if (offset==0) { \
return &array; \
} else { \
return array[TSRM_UNSHUFFLE_RSRC_ID(offset)]; \
}
#endif
#ifdef TSRM_WIN32
static DWORD tls_key;
# define tsrm_tls_set(what) TlsSetValue(tls_key, (void*)(what))
# define tsrm_tls_get() TlsGetValue(tls_key)
#else
static pthread_key_t tls_key;
# define tsrm_tls_set(what) pthread_setspecific(tls_key, (void*)(what))
# define tsrm_tls_get() pthread_getspecific(tls_key)
#endif
TSRM_TLS uint8_t in_main_thread = 0;
TSRM_TLS uint8_t is_thread_shutdown = 0;
/* Startup TSRM (call once for the entire process) */
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, const char *debug_filename)
{/*{{{*/
#ifdef TSRM_WIN32
tls_key = TlsAlloc();
#else
pthread_key_create(&tls_key, 0);
#endif
/* ensure singleton */
in_main_thread = 1;
is_thread_shutdown = 0;
tsrm_error_file = stderr;
tsrm_error_set(debug_level, debug_filename);
tsrm_tls_table_size = expected_threads;
tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
if (!tsrm_tls_table) {
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
is_thread_shutdown = 1;
return 0;
}
id_count=0;
resource_types_table_size = expected_resources;
resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
if (!resource_types_table) {
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
is_thread_shutdown = 1;
free(tsrm_tls_table);
return 0;
}
tsmm_mutex = tsrm_mutex_alloc();
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
tsrm_reserved_pos = 0;
tsrm_reserved_size = 0;
tsrm_env_mutex = tsrm_mutex_alloc();
return 1;
}/*}}}*/
/* Shutdown TSRM (call once for the entire process) */
TSRM_API void tsrm_shutdown(void)
{/*{{{*/
int i;
if (is_thread_shutdown) {
/* shutdown must only occur once */
return;
}
is_thread_shutdown = 1;
if (!in_main_thread) {
/* only the main thread may shutdown tsrm */
return;
}
for (i=0; i<tsrm_tls_table_size; i++) {
tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
while (p) {
int j;
next_p = p->next;
for (j=0; j<p->count; j++) {
if (p->storage[j]) {
if (resource_types_table && !resource_types_table[j].done && resource_types_table[j].dtor) {
resource_types_table[j].dtor(p->storage[j]);
}
if (!resource_types_table[j].fast_offset) {
free(p->storage[j]);
}
}
}
free(p->storage);
free(p);
p = next_p;
}
}
free(tsrm_tls_table);
free(resource_types_table);
tsrm_mutex_free(tsmm_mutex);
tsrm_mutex_free(tsrm_env_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
if (tsrm_error_file!=stderr) {
fclose(tsrm_error_file);
}
#ifdef TSRM_WIN32
TlsFree(tls_key);
#else
pthread_setspecific(tls_key, 0);
pthread_key_delete(tls_key);
#endif
if (tsrm_shutdown_handler) {
tsrm_shutdown_handler();
}
tsrm_new_thread_begin_handler = NULL;
tsrm_new_thread_end_handler = NULL;
tsrm_shutdown_handler = NULL;
tsrm_reserved_pos = 0;
tsrm_reserved_size = 0;
}/*}}}*/
/* {{{ */
/* environ lock api */
TSRM_API void tsrm_env_lock(void) {
tsrm_mutex_lock(tsrm_env_mutex);
}
TSRM_API void tsrm_env_unlock(void) {
tsrm_mutex_unlock(tsrm_env_mutex);
} /* }}} */
/* enlarge the arrays for the already active threads */
static void tsrm_update_active_threads(void)
{/*{{{*/
int i;
for (i=0; i<tsrm_tls_table_size; i++) {
tsrm_tls_entry *p = tsrm_tls_table[i];
while (p) {
if (p->count < id_count) {
int j;
p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
for (j=p->count; j<id_count; j++) {
if (resource_types_table[j].fast_offset) {
p->storage[j] = (void *) (((char*)p) + resource_types_table[j].fast_offset);
} else {
p->storage[j] = (void *) malloc(resource_types_table[j].size);
}
if (resource_types_table[j].ctor) {
resource_types_table[j].ctor(p->storage[j]);
}
}
p->count = id_count;
}
p = p->next;
}
}
}/*}}}*/
/* allocates a new thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
tsrm_mutex_lock(tsmm_mutex);
/* obtain a resource id */
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
/* store the new resource type in the resource sizes table */
if (resource_types_table_size < id_count) {
tsrm_resource_type *_tmp;
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
if (!_tmp) {
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
*rsrc_id = 0;
return 0;
}
resource_types_table = _tmp;
resource_types_table_size = id_count;
}
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
tsrm_update_active_threads();
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
return *rsrc_id;
}/*}}}*/
/* Reserve space for fast thread-safe-resources */
TSRM_API void tsrm_reserve(size_t size)
{/*{{{*/
tsrm_reserved_pos = 0;
tsrm_reserved_size = TSRM_ALIGNED_SIZE(size);
}/*}}}*/
/* allocates a new fast thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new fast resource id, %d bytes", size));
tsrm_mutex_lock(tsmm_mutex);
/* obtain a resource id */
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
size = TSRM_ALIGNED_SIZE(size);
if (tsrm_reserved_size - tsrm_reserved_pos < size) {
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate space for fast resource"));
*rsrc_id = 0;
*offset = 0;
return 0;
}
*offset = TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_pos;
tsrm_reserved_pos += size;
/* store the new resource type in the resource sizes table */
if (resource_types_table_size < id_count) {
tsrm_resource_type *_tmp;
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
if (!_tmp) {
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
*rsrc_id = 0;
return 0;
}
resource_types_table = _tmp;
resource_types_table_size = id_count;
}
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = *offset;
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
tsrm_update_active_threads();
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
return *rsrc_id;
}/*}}}*/
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
{/*{{{*/
int i;
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
(*thread_resources_ptr) = (tsrm_tls_entry *) malloc(TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_size);
(*thread_resources_ptr)->storage = NULL;
if (id_count > 0) {
(*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
}
(*thread_resources_ptr)->count = id_count;
(*thread_resources_ptr)->thread_id = thread_id;
(*thread_resources_ptr)->next = NULL;
/* Set thread local storage to this new thread resources structure */
tsrm_tls_set(*thread_resources_ptr);
TSRMLS_CACHE = *thread_resources_ptr;
if (tsrm_new_thread_begin_handler) {
tsrm_new_thread_begin_handler(thread_id);
}
for (i=0; i<id_count; i++) {
if (resource_types_table[i].done) {
(*thread_resources_ptr)->storage[i] = NULL;
} else {
if (resource_types_table[i].fast_offset) {
(*thread_resources_ptr)->storage[i] = (void *) (((char*)(*thread_resources_ptr)) + resource_types_table[i].fast_offset);
} else {
(*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
}
if (resource_types_table[i].ctor) {
resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
}
}
}
if (tsrm_new_thread_end_handler) {
tsrm_new_thread_end_handler(thread_id);
}
tsrm_mutex_unlock(tsmm_mutex);
}/*}}}*/
/* fetches the requested resource for the current thread */
TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
{/*{{{*/
THREAD_T thread_id;
int hash_value;
tsrm_tls_entry *thread_resources;
if (!th_id) {
/* Fast path for looking up the resources for the current
* thread. Its used by just about every call to
* ts_resource_ex(). This avoids the need for a mutex lock
* and our hashtable lookup.
*/
thread_resources = tsrm_tls_get();
if (thread_resources) {
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
/* Read a specific resource from the thread's resources.
* This is called outside of a mutex, so have to be aware about external
* changes to the structure as we read it.
*/
TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
}
thread_id = tsrm_thread_id();
} else {
thread_id = *th_id;
}
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
tsrm_mutex_lock(tsmm_mutex);
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
thread_resources = tsrm_tls_table[hash_value];
if (!thread_resources) {
allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
return ts_resource_ex(id, &thread_id);
} else {
do {
if (thread_resources->thread_id == thread_id) {
break;
}
if (thread_resources->next) {
thread_resources = thread_resources->next;
} else {
allocate_new_resource(&thread_resources->next, thread_id);
return ts_resource_ex(id, &thread_id);
/*
* thread_resources = thread_resources->next;
* break;
*/
}
} while (thread_resources);
}
tsrm_mutex_unlock(tsmm_mutex);
/* Read a specific resource from the thread's resources.
* This is called outside of a mutex, so have to be aware about external
* changes to the structure as we read it.
*/
TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
}/*}}}*/
/* frees all resources allocated for the current thread */
void ts_free_thread(void)
{/*{{{*/
tsrm_tls_entry *thread_resources;
int i;
THREAD_T thread_id = tsrm_thread_id();
int hash_value;
tsrm_tls_entry *last=NULL;
TSRM_ASSERT(!in_main_thread);
tsrm_mutex_lock(tsmm_mutex);
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
thread_resources = tsrm_tls_table[hash_value];
while (thread_resources) {
if (thread_resources->thread_id == thread_id) {
for (i=0; i<thread_resources->count; i++) {
if (resource_types_table[i].dtor) {
resource_types_table[i].dtor(thread_resources->storage[i]);
}
}
for (i=0; i<thread_resources->count; i++) {
if (!resource_types_table[i].fast_offset) {
free(thread_resources->storage[i]);
}
}
free(thread_resources->storage);
if (last) {
last->next = thread_resources->next;
} else {
tsrm_tls_table[hash_value] = thread_resources->next;
}
tsrm_tls_set(0);
free(thread_resources);
break;
}
if (thread_resources->next) {
last = thread_resources;
}
thread_resources = thread_resources->next;
}
tsrm_mutex_unlock(tsmm_mutex);
}/*}}}*/
/* deallocates all occurrences of a given id */
void ts_free_id(ts_rsrc_id id)
{/*{{{*/
int i;
int j = TSRM_UNSHUFFLE_RSRC_ID(id);
tsrm_mutex_lock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id));
if (tsrm_tls_table) {
for (i=0; i<tsrm_tls_table_size; i++) {
tsrm_tls_entry *p = tsrm_tls_table[i];
while (p) {
if (p->count > j && p->storage[j]) {
if (resource_types_table && resource_types_table[j].dtor) {
resource_types_table[j].dtor(p->storage[j]);
}
if (!resource_types_table[j].fast_offset) {
free(p->storage[j]);
}
p->storage[j] = NULL;
}
p = p->next;
}
}
}
resource_types_table[j].done = 1;
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id));
}/*}}}*/
/*
* Utility Functions
*/
/* Obtain the current thread id */
TSRM_API THREAD_T tsrm_thread_id(void)
{/*{{{*/
#ifdef TSRM_WIN32
return GetCurrentThreadId();
#else
return pthread_self();
#endif
}/*}}}*/
/* Allocate a mutex */
TSRM_API MUTEX_T tsrm_mutex_alloc(void)
{/*{{{*/
MUTEX_T mutexp;
#ifdef TSRM_WIN32
mutexp = malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(mutexp);
#else
mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(mutexp,NULL);
#endif
#ifdef THR_DEBUG
printf("Mutex created thread: %d\n",mythreadid());
#endif
return( mutexp );
}/*}}}*/
/* Free a mutex */
TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
{/*{{{*/
if (mutexp) {
#ifdef TSRM_WIN32
DeleteCriticalSection(mutexp);
free(mutexp);
#else
pthread_mutex_destroy(mutexp);
free(mutexp);
#endif
}
#ifdef THR_DEBUG
printf("Mutex freed thread: %d\n",mythreadid());
#endif
}/*}}}*/
/*
Lock a mutex.
A return value of 0 indicates success
*/
TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
EnterCriticalSection(mutexp);
return 0;
#else
return pthread_mutex_lock(mutexp);
#endif
}/*}}}*/
/*
Unlock a mutex.
A return value of 0 indicates success
*/
TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
LeaveCriticalSection(mutexp);
return 0;
#else
return pthread_mutex_unlock(mutexp);
#endif
}/*}}}*/
/*
Changes the signal mask of the calling thread
*/
#ifdef HAVE_SIGPROCMASK
TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Changed sigmask in thread: %ld", tsrm_thread_id()));
return pthread_sigmask(how, set, oldset);
}/*}}}*/
#endif
TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
{/*{{{*/
void *retval = (void *) tsrm_new_thread_begin_handler;
tsrm_new_thread_begin_handler = new_thread_begin_handler;
return retval;
}/*}}}*/
TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
{/*{{{*/
void *retval = (void *) tsrm_new_thread_end_handler;
tsrm_new_thread_end_handler = new_thread_end_handler;
return retval;
}/*}}}*/
TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler)
{/*{{{*/
void *retval = (void *) tsrm_shutdown_handler;
tsrm_shutdown_handler = shutdown_handler;
return retval;
}/*}}}*/
/*
* Debug support
*/
#ifdef TSRM_DEBUG
int tsrm_error(int level, const char *format, ...)
{/*{{{*/
if (level<=tsrm_error_level) {
va_list args;
int size;
fprintf(tsrm_error_file, "TSRM: ");
va_start(args, format);
size = vfprintf(tsrm_error_file, format, args);
va_end(args);
fprintf(tsrm_error_file, "\n");
fflush(tsrm_error_file);
return size;
} else {
return 0;
}
}/*}}}*/
#endif
void tsrm_error_set(int level, const char *debug_filename)
{/*{{{*/
tsrm_error_level = level;
#ifdef TSRM_DEBUG
if (tsrm_error_file!=stderr) { /* close files opened earlier */
fclose(tsrm_error_file);
}
if (debug_filename) {
tsrm_error_file = fopen(debug_filename, "w");
if (!tsrm_error_file) {
tsrm_error_file = stderr;
}
} else {
tsrm_error_file = stderr;
}
#endif
}/*}}}*/
TSRM_API void *tsrm_get_ls_cache(void)
{/*{{{*/
return tsrm_tls_get();
}/*}}}*/
/* Returns offset of tsrm_ls_cache slot from Thread Control Block address */
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void)
{/*{{{*/
#if defined(__APPLE__) && defined(__x86_64__)
// TODO: Implement support for fast JIT ZTS code ???
return 0;
#elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__)
size_t ret;
asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
: "=r" (ret));
return ret;
#elif defined(__i386__) && defined(__GNUC__) && !defined(__FreeBSD__)
size_t ret;
asm ("leal _tsrm_ls_cache@ntpoff,%0"
: "=r" (ret));
return ret;
#elif defined(__aarch64__)
size_t ret;
# ifdef __APPLE__
// Points to struct TLVDecriptor for _tsrm_ls_cache in macOS.
asm("adrp %0, #__tsrm_ls_cache@TLVPPAGE\n\t"
"ldr %0, [%0, #__tsrm_ls_cache@TLVPPAGEOFF]"
: "=r" (ret));
# else
asm("mov %0, xzr\n\t"
"add %0, %0, #:tprel_hi12:_tsrm_ls_cache, lsl #12\n\t"
"add %0, %0, #:tprel_lo12_nc:_tsrm_ls_cache"
: "=r" (ret));
# endif
return ret;
#else
return 0;
#endif
}/*}}}*/
TSRM_API uint8_t tsrm_is_main_thread(void)
{/*{{{*/
return in_main_thread;
}/*}}}*/
TSRM_API uint8_t tsrm_is_shutdown(void)
{/*{{{*/
return is_thread_shutdown;
}/*}}}*/
TSRM_API const char *tsrm_api_name(void)
{/*{{{*/
#ifdef TSRM_WIN32
return "Windows Threads";
#else
return "POSIX Threads";
#endif
}/*}}}*/
#endif /* ZTS */
-194
View File
@@ -1,194 +0,0 @@
/*
+----------------------------------------------------------------------+
| Thread Safe Resource Manager |
+----------------------------------------------------------------------+
| Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
| This source file is subject to the TSRM license, that is bundled |
| with this package in the file LICENSE |
+----------------------------------------------------------------------+
| Authors: Zeev Suraski <zeev@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef TSRM_H
#define TSRM_H
#if !defined(__CYGWIN__) && defined(WIN32)
# define TSRM_WIN32
# include "Zend/zend_config.w32.h"
#else
# include "main/php_config.h"
#endif
#include "main/php_stdint.h"
#ifdef TSRM_WIN32
# ifdef TSRM_EXPORTS
# define TSRM_API __declspec(dllexport)
# else
# define TSRM_API __declspec(dllimport)
# endif
#elif defined(__GNUC__) && __GNUC__ >= 4
# define TSRM_API __attribute__ ((visibility("default")))
#else
# define TSRM_API
#endif
typedef intptr_t tsrm_intptr_t;
typedef uintptr_t tsrm_uintptr_t;
/* Only compile multi-threading functions if we're in ZTS mode */
#ifdef ZTS
#ifdef TSRM_WIN32
# ifndef TSRM_INCLUDE_FULL_WINDOWS_HEADERS
# define WIN32_LEAN_AND_MEAN
# endif
#else
# include <pthread.h>
#endif
#if SIZEOF_SIZE_T == 4
# define TSRM_ALIGNED_SIZE(size) \
(((size) + INT32_C(15)) & ~INT32_C(15))
#else
# define TSRM_ALIGNED_SIZE(size) \
(((size) + INT64_C(15)) & ~INT64_C(15))
#endif
typedef int ts_rsrc_id;
/* Define THREAD_T and MUTEX_T */
#ifdef TSRM_WIN32
# define THREAD_T DWORD
# define MUTEX_T CRITICAL_SECTION *
#else
# define THREAD_T pthread_t
# define MUTEX_T pthread_mutex_t *
#endif
#include <signal.h>
typedef void (*ts_allocate_ctor)(void *);
typedef void (*ts_allocate_dtor)(void *);
#define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts
#ifdef __cplusplus
extern "C" {
#endif
/* startup/shutdown */
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, const char *debug_filename);
TSRM_API void tsrm_shutdown(void);
/* environ lock API */
TSRM_API void tsrm_env_lock(void);
TSRM_API void tsrm_env_unlock(void);
/* allocates a new thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
/* Fast resource in reserved (pre-allocated) space */
TSRM_API void tsrm_reserve(size_t size);
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
/* fetches the requested resource for the current thread */
TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id);
#define ts_resource(id) ts_resource_ex(id, NULL)
/* frees all resources allocated for the current thread */
TSRM_API void ts_free_thread(void);
/* deallocates all occurrences of a given id */
TSRM_API void ts_free_id(ts_rsrc_id id);
/* Debug support */
#define TSRM_ERROR_LEVEL_ERROR 1
#define TSRM_ERROR_LEVEL_CORE 2
#define TSRM_ERROR_LEVEL_INFO 3
typedef void (*tsrm_thread_begin_func_t)(THREAD_T thread_id);
typedef void (*tsrm_thread_end_func_t)(THREAD_T thread_id);
typedef void (*tsrm_shutdown_func_t)(void);
TSRM_API int tsrm_error(int level, const char *format, ...);
TSRM_API void tsrm_error_set(int level, const char *debug_filename);
/* utility functions */
TSRM_API THREAD_T tsrm_thread_id(void);
TSRM_API MUTEX_T tsrm_mutex_alloc(void);
TSRM_API void tsrm_mutex_free(MUTEX_T mutexp);
TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp);
TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp);
#ifdef HAVE_SIGPROCMASK
TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset);
#endif
TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler);
TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler);
TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler);
TSRM_API void *tsrm_get_ls_cache(void);
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void);
TSRM_API uint8_t tsrm_is_main_thread(void);
TSRM_API uint8_t tsrm_is_shutdown(void);
TSRM_API const char *tsrm_api_name(void);
#ifdef TSRM_WIN32
# define TSRM_TLS __declspec(thread)
#else
# define TSRM_TLS __thread
#endif
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
#if !__has_attribute(tls_model) || defined(__FreeBSD__) || defined(__MUSL__)
# define TSRM_TLS_MODEL_ATTR
#elif __PIC__
# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("initial-exec")))
#else
# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("local-exec")))
#endif
#define TSRM_SHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)+1)
#define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1)
#define TSRMG(id, type, element) (TSRMG_BULK(id, type)->element)
#define TSRMG_BULK(id, type) ((type) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(id)])
#define TSRMG_FAST(offset, type, element) (TSRMG_FAST_BULK(offset, type)->element)
#define TSRMG_FAST_BULK(offset, type) ((type) (((char*) tsrm_get_ls_cache())+(offset)))
#define TSRMG_STATIC(id, type, element) (TSRMG_BULK_STATIC(id, type)->element)
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
#define TSRMLS_CACHE _tsrm_ls_cache
#ifdef __cplusplus
}
#endif
#else /* non ZTS */
#define tsrm_env_lock()
#define tsrm_env_unlock()
#define TSRMG_STATIC(id, type, element)
#define TSRMLS_CACHE_EXTERN()
#define TSRMLS_CACHE_DEFINE()
#define TSRMLS_CACHE_UPDATE()
#define TSRMLS_CACHE
#define TSRM_TLS
#endif /* ZTS */
#endif /* TSRM_H */
-4
View File
@@ -1,4 +0,0 @@
// vim:ft=javascript
ADD_SOURCES("TSRM", "TSRM.c tsrm_win32.c");
ADD_FLAG("CFLAGS_BD_TSRM", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
-140
View File
@@ -1,140 +0,0 @@
dnl Copyright (c) 1999, 2000 Sascha Schumann. All rights reserved.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in
dnl the documentation and/or other materials provided with the
dnl distribution.
dnl
dnl THIS SOFTWARE IS PROVIDED BY SASCHA SCHUMANN ``AS IS'' AND ANY
dnl EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
dnl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
dnl PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SASCHA SCHUMANN OR
dnl HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
dnl NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
dnl LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
dnl HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
dnl STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
dnl ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
dnl OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl PTHREADS_FLAGS
dnl
dnl Set some magic defines to achieve POSIX threads conformance.
dnl
AC_DEFUN([PTHREADS_FLAGS],[
if test -z "$host_alias" && test -n "$host"; then
host_alias=$host
fi
if test -z "$host_alias"; then
AC_MSG_ERROR(host_alias is not set. Make sure to run config.guess)
fi
case $host_alias in
*solaris*)
PTHREAD_FLAGS="-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT";;
*freebsd*)
PTHREAD_FLAGS="-D_REENTRANT -D_THREAD_SAFE";;
*linux*)
PTHREAD_FLAGS=-D_REENTRANT;;
*aix*)
PTHREAD_FLAGS=-D_THREAD_SAFE;;
*irix*)
PTHREAD_FLAGS=-D_POSIX_THREAD_SAFE_FUNCTIONS;;
*hpux*)
PTHREAD_FLAGS=-D_REENTRANT;;
*sco*)
PTHREAD_FLAGS=-D_REENTRANT;;
esac
if test -n "$PTHREAD_FLAGS"; then
CPPFLAGS="$CPPFLAGS $PTHREAD_FLAGS"
fi
])
dnl
dnl PTHREADS_CHECK_COMPILE
dnl
dnl Check whether the current setup can use POSIX threads calls.
dnl
AC_DEFUN([PTHREADS_CHECK_COMPILE], [
AC_LINK_IFELSE([ AC_LANG_SOURCE([
#include <pthread.h>
#include <stddef.h>
void *thread_routine(void *data) {
return data;
}
int main() {
pthread_t thd;
pthread_mutexattr_t mattr;
int data = 1;
pthread_mutexattr_init(&mattr);
return pthread_create(&thd, NULL, thread_routine, &data);
} ]) ], [
pthreads_checked=yes
], [
pthreads_checked=no
]
) ] )
dnl
dnl PTHREADS_CHECK
dnl
dnl Try to find a way to enable POSIX threads.
dnl
dnl Magic flags
dnl -kthread gcc (FreeBSD)
dnl -Kthread UDK cc (UnixWare)
dnl -mt WorkShop cc (Solaris)
dnl -mthreads gcc (AIX)
dnl -pthread gcc (Linux, FreeBSD, NetBSD, OpenBSD)
dnl -pthreads gcc (Solaris)
dnl -qthreaded AIX cc V5
dnl -threads gcc (HP-UX)
dnl
AC_DEFUN([PTHREADS_CHECK],[
AC_CACHE_CHECK(for pthreads_cflags,ac_cv_pthreads_cflags,[
ac_cv_pthreads_cflags=
if test "$pthreads_working" != "yes"; then
for flag in -kthread -pthread -pthreads -mthreads -Kthread -threads -mt -qthreaded; do
ac_save=$CFLAGS
CFLAGS="$CFLAGS $flag"
PTHREADS_CHECK_COMPILE
CFLAGS=$ac_save
if test "$pthreads_checked" = "yes"; then
ac_cv_pthreads_cflags=$flag
break
fi
done
fi
])
AC_CACHE_CHECK(for pthreads_lib, ac_cv_pthreads_lib,[
ac_cv_pthreads_lib=
if test "$pthreads_working" != "yes"; then
for lib in pthread pthreads c_r; do
ac_save=$LIBS
LIBS="$LIBS -l$lib"
PTHREADS_CHECK_COMPILE
LIBS=$ac_save
if test "$pthreads_checked" = "yes"; then
ac_cv_pthreads_lib=$lib
break
fi
done
fi
])
if test "x$ac_cv_pthreads_cflags" != "x" -o "x$ac_cv_pthreads_lib" != "x"; then
pthreads_working="yes"
fi
])
-17
View File
@@ -1,17 +0,0 @@
dnl This file contains TSRM specific autoconf macros.
dnl
dnl TSRM_CHECK_PTHREADS
dnl
AC_DEFUN([TSRM_CHECK_PTHREADS],[
PTHREADS_CHECK
if test "$pthreads_working" != "yes"; then
AC_MSG_ERROR(Your system seems to lack POSIX threads.)
fi
AC_DEFINE(PTHREADS, 1, Whether to use Pthreads)
AC_MSG_CHECKING(for POSIX threads)
AC_MSG_RESULT(yes)
])
-825
View File
@@ -1,825 +0,0 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Daniel Beulshausen <daniel@php4win.de> |
+----------------------------------------------------------------------+
*/
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <time.h>
#include <errno.h>
#define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
#include "SAPI.h"
#include "TSRM.h"
#ifdef TSRM_WIN32
#include <Sddl.h>
#include "tsrm_win32.h"
#include "zend_virtual_cwd.h"
#include "win32/ioutil.h"
#ifdef ZTS
static ts_rsrc_id win32_globals_id;
#else
static tsrm_win32_globals win32_globals;
#endif
static void tsrm_win32_ctor(tsrm_win32_globals *globals)
{/*{{{*/
#ifdef ZTS
TSRMLS_CACHE_UPDATE();
#endif
globals->process = NULL;
globals->shm = NULL;
globals->process_size = 0;
globals->shm_size = 0;
globals->comspec = _strdup("cmd.exe");
/* Set it to INVALID_HANDLE_VALUE
* It will be initialized correctly in tsrm_win32_access or set to
* NULL if no impersonation has been done.
* the impersonated token can't be set here as the impersonation
* will happen later, in fcgi_accept_request (or whatever is the
* SAPI being used).
*/
globals->impersonation_token = INVALID_HANDLE_VALUE;
globals->impersonation_token_sid = NULL;
}/*}}}*/
static void tsrm_win32_dtor(tsrm_win32_globals *globals)
{/*{{{*/
shm_pair *ptr;
if (globals->process) {
free(globals->process);
}
if (globals->shm) {
for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
UnmapViewOfFile(ptr->addr);
CloseHandle(ptr->segment);
UnmapViewOfFile(ptr->descriptor);
CloseHandle(ptr->info);
}
free(globals->shm);
}
free(globals->comspec);
if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
CloseHandle(globals->impersonation_token);
}
if (globals->impersonation_token_sid) {
free(globals->impersonation_token_sid);
}
}/*}}}*/
TSRM_API void tsrm_win32_startup(void)
{/*{{{*/
#ifdef ZTS
ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
#else
tsrm_win32_ctor(&win32_globals);
#endif
}/*}}}*/
TSRM_API void tsrm_win32_shutdown(void)
{/*{{{*/
#ifndef ZTS
tsrm_win32_dtor(&win32_globals);
#endif
}/*}}}*/
const char * tsrm_win32_get_path_sid_key(const char *pathname, size_t pathname_len, size_t *key_len)
{/*{{{*/
PSID pSid = TWG(impersonation_token_sid);
char *ptcSid = NULL;
char *bucket_key = NULL;
size_t ptc_sid_len;
if (!pSid) {
*key_len = pathname_len;
return pathname;
}
if (!ConvertSidToStringSid(pSid, &ptcSid)) {
*key_len = 0;
return NULL;
}
ptc_sid_len = strlen(ptcSid);
*key_len = pathname_len + ptc_sid_len;
bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *key_len + 1);
if (!bucket_key) {
LocalFree(ptcSid);
*key_len = 0;
return NULL;
}
memcpy(bucket_key, ptcSid, ptc_sid_len);
memcpy(bucket_key + ptc_sid_len, pathname, pathname_len + 1);
LocalFree(ptcSid);
return bucket_key;
}/*}}}*/
PSID tsrm_win32_get_token_sid(HANDLE hToken)
{/*{{{*/
DWORD dwLength = 0;
PTOKEN_USER pTokenUser = NULL;
DWORD sid_len;
PSID pResultSid = NULL;
/* Get the actual size of the TokenUser structure */
if (!GetTokenInformation(
hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto Finished;
}
pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
if (pTokenUser == NULL) {
goto Finished;
}
}
/* and fetch it now */
if (!GetTokenInformation(
hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
goto Finished;
}
sid_len = GetLengthSid(pTokenUser->User.Sid);
/* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
pResultSid = malloc(sid_len);
if (!pResultSid) {
goto Finished;
}
if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
goto Finished;
}
HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
return pResultSid;
Finished:
if (pResultSid) {
free(pResultSid);
}
/* Free the buffer for the token groups. */
if (pTokenUser != NULL) {
HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
}
return NULL;
}/*}}}*/
TSRM_API int tsrm_win32_access(const char *pathname, int mode)
{/*{{{*/
time_t t;
HANDLE thread_token = NULL;
PSID token_sid;
SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
DWORD priv_set_length = sizeof(PRIVILEGE_SET);
PRIVILEGE_SET privilege_set = {0};
DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
BYTE * psec_desc = NULL;
BOOL fAccess = FALSE;
realpath_cache_bucket * bucket = NULL;
char real_path[MAXPATHLEN] = {0};
if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
if(tsrm_realpath(pathname, real_path) == NULL) {
SET_ERRNO_FROM_WIN32_CODE(ERROR_FILE_NOT_FOUND);
return -1;
}
pathname = real_path;
}
PHP_WIN32_IOUTIL_INIT_W(pathname)
if (!pathw) {
return -1;
}
/* Either access call failed, or the mode was asking for a specific check.*/
int ret = php_win32_ioutil_access_w(pathw, mode);
if (0 > ret || X_OK == mode || F_OK == mode) {
PHP_WIN32_IOUTIL_CLEANUP_W()
return ret;
}
/* Only in NTS when impersonate==1 (aka FastCGI) */
/*
AccessCheck() requires an impersonation token. We first get a primary
token and then create a duplicate impersonation token. The
impersonation token is not actually assigned to the thread, but is
used in the call to AccessCheck. Thus, this function itself never
impersonates, but does use the identity of the thread. If the thread
was impersonating already, this function uses that impersonation context.
*/
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
if (GetLastError() == ERROR_NO_TOKEN) {
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
TWG(impersonation_token) = NULL;
goto Finished;
}
}
}
/* token_sid will be freed in tsrmwin32_dtor */
token_sid = tsrm_win32_get_token_sid(thread_token);
if (!token_sid) {
if (TWG(impersonation_token_sid)) {
free(TWG(impersonation_token_sid));
}
TWG(impersonation_token_sid) = NULL;
goto Finished;
}
/* Different identity, we need a new impersonated token as well */
if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
if (TWG(impersonation_token_sid)) {
free(TWG(impersonation_token_sid));
}
TWG(impersonation_token_sid) = token_sid;
/* Duplicate the token as impersonated token */
if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
goto Finished;
}
} else {
/* we already have it, free it then */
free(token_sid);
}
if (CWDG(realpath_cache_size_limit)) {
t = time(0);
bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
if(bucket == NULL && !real_path[0]) {
/* We used the pathname directly. Call tsrm_realpath */
/* so that entry is created in realpath cache */
if(tsrm_realpath(pathname, real_path) != NULL) {
pathname = real_path;
bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
PHP_WIN32_IOUTIL_REINIT_W(pathname);
}
}
}
/* Do a full access check because access() will only check read-only attribute */
if(mode == 0 || mode > 6) {
if(bucket != NULL && bucket->is_rvalid) {
fAccess = bucket->is_readable;
goto Finished;
}
desired_access = FILE_GENERIC_READ;
} else if(mode <= 2) {
if(bucket != NULL && bucket->is_wvalid) {
fAccess = bucket->is_writable;
goto Finished;
}
desired_access = FILE_GENERIC_WRITE;
} else if(mode <= 4) {
if(bucket != NULL && bucket->is_rvalid) {
fAccess = bucket->is_readable;
goto Finished;
}
desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
} else { // if(mode <= 6)
if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
fAccess = bucket->is_readable & bucket->is_writable;
goto Finished;
}
desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
}
if(TWG(impersonation_token) == NULL) {
goto Finished;
}
/* Get size of security buffer. Call is expected to fail */
if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
goto Finished;
}
psec_desc = (BYTE *)malloc(sec_desc_length);
if(psec_desc == NULL ||
!GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
goto Finished;
}
MapGenericMask(&desired_access, &gen_map);
if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
goto Finished_Impersonate;
}
/* Keep the result in realpath_cache */
if(bucket != NULL) {
if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
bucket->is_rvalid = 1;
bucket->is_readable = fAccess;
}
else if(desired_access == FILE_GENERIC_WRITE) {
bucket->is_wvalid = 1;
bucket->is_writable = fAccess;
} else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
bucket->is_rvalid = 1;
bucket->is_readable = fAccess;
bucket->is_wvalid = 1;
bucket->is_writable = fAccess;
}
}
Finished_Impersonate:
if(psec_desc != NULL) {
free(psec_desc);
psec_desc = NULL;
}
Finished:
if(thread_token != NULL) {
CloseHandle(thread_token);
}
PHP_WIN32_IOUTIL_CLEANUP_W()
if(fAccess == FALSE) {
errno = EACCES;
return errno;
} else {
return 0;
}
}/*}}}*/
static process_pair *process_get(FILE *stream)
{/*{{{*/
process_pair *ptr;
process_pair *newptr;
for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
if (ptr->stream == stream) {
break;
}
}
if (ptr < (TWG(process) + TWG(process_size))) {
return ptr;
}
newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
if (newptr == NULL) {
return NULL;
}
TWG(process) = newptr;
ptr = newptr + TWG(process_size);
TWG(process_size)++;
return ptr;
}/*}}}*/
static shm_pair *shm_get(key_t key, void *addr)
{/*{{{*/
shm_pair *ptr;
shm_pair *newptr;
for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
if (!ptr->descriptor) {
continue;
}
if (!addr && ptr->descriptor->shm_perm.key == key) {
break;
} else if (ptr->addr == addr) {
break;
}
}
if (ptr < (TWG(shm) + TWG(shm_size))) {
return ptr;
}
newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
if (newptr == NULL) {
return NULL;
}
TWG(shm) = newptr;
ptr = newptr + TWG(shm_size);
TWG(shm_size)++;
memset(ptr, 0, sizeof(*ptr));
return ptr;
}/*}}}*/
static HANDLE dupHandle(HANDLE fh, BOOL inherit)
{/*{{{*/
HANDLE copy, self = GetCurrentProcess();
if (!DuplicateHandle(self, fh, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
return NULL;
}
return copy;
}/*}}}*/
TSRM_API FILE *popen(const char *command, const char *type)
{/*{{{*/
return popen_ex(command, type, NULL, NULL);
}/*}}}*/
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, const char *env)
{/*{{{*/
FILE *stream = NULL;
int fno, type_len, read, mode;
STARTUPINFOW startup;
PROCESS_INFORMATION process;
SECURITY_ATTRIBUTES security;
HANDLE in, out;
DWORD dwCreateFlags = 0;
BOOL res;
process_pair *proc;
char *cmd = NULL;
wchar_t *cmdw = NULL, *cwdw = NULL, *envw = NULL;
char *ptype = (char *)type;
HANDLE thread_token = NULL;
HANDLE token_user = NULL;
BOOL asuser = TRUE;
if (!type) {
return NULL;
}
type_len = (int)strlen(type);
if (type_len < 1 || type_len > 2) {
return NULL;
}
if (ptype[0] != 'r' && ptype[0] != 'w') {
return NULL;
}
if (type_len > 1 && (ptype[1] != 'b' && ptype[1] != 't')) {
return NULL;
}
cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /s /c ")+2);
if (!cmd) {
return NULL;
}
sprintf(cmd, "%s /s /c \"%s\"", TWG(comspec), command);
cmdw = php_win32_cp_any_to_w(cmd);
if (!cmdw) {
free(cmd);
return NULL;
}
if (cwd) {
cwdw = php_win32_ioutil_any_to_w(cwd);
if (!cwdw) {
free(cmd);
free(cmdw);
return NULL;
}
}
security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.bInheritHandle = TRUE;
security.lpSecurityDescriptor = NULL;
if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
free(cmdw);
free(cwdw);
free(cmd);
return NULL;
}
memset(&startup, 0, sizeof(STARTUPINFOW));
memset(&process, 0, sizeof(PROCESS_INFORMATION));
startup.cb = sizeof(STARTUPINFOW);
startup.dwFlags = STARTF_USESTDHANDLES;
startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
read = (type[0] == 'r') ? TRUE : FALSE;
mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
if (read) {
in = dupHandle(in, FALSE);
startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startup.hStdOutput = out;
} else {
out = dupHandle(out, FALSE);
startup.hStdInput = in;
startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
}
dwCreateFlags = NORMAL_PRIORITY_CLASS;
if (strcmp(sapi_module.name, "cli") != 0) {
dwCreateFlags |= CREATE_NO_WINDOW;
}
/* Get a token with the impersonated user. */
if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
} else {
DWORD err = GetLastError();
if (err == ERROR_NO_TOKEN) {
asuser = FALSE;
}
}
envw = php_win32_cp_env_any_to_w(env);
if (envw) {
dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
} else {
if (env) {
free(cmd);
free(cmdw);
free(cwdw);
return NULL;
}
}
if (asuser) {
res = CreateProcessAsUserW(token_user, NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
CloseHandle(token_user);
} else {
res = CreateProcessW(NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
}
free(cmd);
free(cmdw);
free(cwdw);
free(envw);
if (!res) {
return NULL;
}
CloseHandle(process.hThread);
proc = process_get(NULL);
if (read) {
fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
CloseHandle(out);
} else {
fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
CloseHandle(in);
}
stream = _fdopen(fno, type);
proc->prochnd = process.hProcess;
proc->stream = stream;
return stream;
}/*}}}*/
TSRM_API int pclose(FILE *stream)
{/*{{{*/
DWORD termstat = 0;
process_pair *process;
if ((process = process_get(stream)) == NULL) {
return 0;
}
fflush(process->stream);
fclose(process->stream);
WaitForSingleObject(process->prochnd, INFINITE);
GetExitCodeProcess(process->prochnd, &termstat);
process->stream = NULL;
CloseHandle(process->prochnd);
return termstat;
}/*}}}*/
TSRM_API int shmget(key_t key, size_t size, int flags)
{/*{{{*/
shm_pair *shm;
char shm_segment[26], shm_info[29];
HANDLE shm_handle = NULL, info_handle = NULL;
BOOL created = FALSE;
if (key != IPC_PRIVATE) {
snprintf(shm_segment, sizeof(shm_segment), "TSRM_SHM_SEGMENT:%d", key);
snprintf(shm_info, sizeof(shm_info), "TSRM_SHM_DESCRIPTOR:%d", key);
shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
}
if (!shm_handle && !info_handle) {
if (flags & IPC_CREAT) {
#if SIZEOF_SIZE_T == 8
DWORD high = size >> 32;
DWORD low = (DWORD)size;
#else
DWORD high = 0;
DWORD low = size;
#endif
shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, high, low, key == IPC_PRIVATE ? NULL : shm_segment);
info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), key == IPC_PRIVATE ? NULL : shm_info);
created = TRUE;
}
if (!shm_handle || !info_handle) {
if (shm_handle) {
CloseHandle(shm_handle);
}
if (info_handle) {
CloseHandle(info_handle);
}
return -1;
}
} else {
if (flags & IPC_EXCL) {
if (shm_handle) {
CloseHandle(shm_handle);
}
if (info_handle) {
CloseHandle(info_handle);
}
return -1;
}
}
shm = shm_get(key, NULL);
if (!shm) {
CloseHandle(shm_handle);
CloseHandle(info_handle);
return -1;
}
shm->segment = shm_handle;
shm->info = info_handle;
shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
if (NULL != shm->descriptor && created) {
shm->descriptor->shm_perm.key = key;
shm->descriptor->shm_segsz = size;
shm->descriptor->shm_ctime = time(NULL);
shm->descriptor->shm_cpid = getpid();
shm->descriptor->shm_perm.mode = flags;
shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
}
if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
if (NULL != shm->segment) {
CloseHandle(shm->segment);
}
UnmapViewOfFile(shm->descriptor);
CloseHandle(shm->info);
return -1;
}
return key;
}/*}}}*/
TSRM_API void *shmat(int key, const void *shmaddr, int flags)
{/*{{{*/
shm_pair *shm = shm_get(key, NULL);
if (!shm->segment) {
return (void*)-1;
}
shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
if (NULL == shm->addr) {
int err = GetLastError();
SET_ERRNO_FROM_WIN32_CODE(err);
return (void*)-1;
}
shm->descriptor->shm_atime = time(NULL);
shm->descriptor->shm_lpid = getpid();
shm->descriptor->shm_nattch++;
return shm->addr;
}/*}}}*/
TSRM_API int shmdt(const void *shmaddr)
{/*{{{*/
shm_pair *shm = shm_get(0, (void*)shmaddr);
int ret;
if (!shm->segment) {
return -1;
}
shm->descriptor->shm_dtime = time(NULL);
shm->descriptor->shm_lpid = getpid();
shm->descriptor->shm_nattch--;
ret = UnmapViewOfFile(shm->addr) ? 0 : -1;
if (!ret && shm->descriptor->shm_nattch <= 0) {
ret = UnmapViewOfFile(shm->descriptor) ? 0 : -1;
shm->descriptor = NULL;
}
return ret;
}/*}}}*/
TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf)
{/*{{{*/
shm_pair *shm = shm_get(key, NULL);
if (!shm->segment) {
return -1;
}
switch (cmd) {
case IPC_STAT:
memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
return 0;
case IPC_SET:
shm->descriptor->shm_ctime = time(NULL);
shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
return 0;
case IPC_RMID:
if (shm->descriptor->shm_nattch < 1) {
shm->descriptor->shm_perm.key = -1;
}
return 0;
default:
return -1;
}
}/*}}}*/
static zend_always_inline void UnixTimeToFileTime(time_t t, LPFILETIME pft) /* {{{ */
{
// Note that LONGLONG is a 64-bit value
LONGLONG ll;
ll = t * 10000000LL + 116444736000000000LL;
pft->dwLowDateTime = (DWORD)ll;
pft->dwHighDateTime = ll >> 32;
}
/* }}} */
TSRM_API int win32_utime(const char *filename, struct utimbuf *buf) /* {{{ */
{
FILETIME mtime, atime;
HANDLE hFile;
PHP_WIN32_IOUTIL_INIT_W(filename)
if (!pathw) {
return -1;
}
hFile = CreateFileW(pathw, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
PHP_WIN32_IOUTIL_CLEANUP_W()
/* OPEN_ALWAYS mode sets the last error to ERROR_ALREADY_EXISTS but
the CreateFile operation succeeds */
if (GetLastError() == ERROR_ALREADY_EXISTS) {
SetLastError(0);
}
if ( hFile == INVALID_HANDLE_VALUE ) {
return -1;
}
if (!buf) {
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &mtime);
atime = mtime;
} else {
UnixTimeToFileTime(buf->modtime, &mtime);
UnixTimeToFileTime(buf->actime, &atime);
}
if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
CloseHandle(hFile);
return -1;
}
CloseHandle(hFile);
return 1;
}
/* }}} */
#endif
-107
View File
@@ -1,107 +0,0 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Daniel Beulshausen <daniel@php4win.de> |
+----------------------------------------------------------------------+
*/
#ifndef TSRM_WIN32_H
#define TSRM_WIN32_H
#include "TSRM.h"
#include <windows.h>
#include <sys/utime.h>
#include "win32/ipc.h"
struct ipc_perm {
key_t key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
};
typedef struct {
FILE *stream;
HANDLE prochnd;
} process_pair;
typedef struct {
void *addr;
HANDLE info;
HANDLE segment;
struct shmid_ds *descriptor;
} shm_pair;
typedef struct {
process_pair *process;
shm_pair *shm;
int process_size;
int shm_size;
char *comspec;
HANDLE impersonation_token;
PSID impersonation_token_sid;
} tsrm_win32_globals;
#ifdef ZTS
# define TWG(v) TSRMG_STATIC(win32_globals_id, tsrm_win32_globals *, v)
TSRMLS_CACHE_EXTERN()
#else
# define TWG(v) (win32_globals.v)
#endif
#define IPC_PRIVATE 0
#define IPC_CREAT 00001000
#define IPC_EXCL 00002000
#define IPC_NOWAIT 00004000
#define IPC_RMID 0
#define IPC_SET 1
#define IPC_STAT 2
#define IPC_INFO 3
#define SHM_R PAGE_READONLY
#define SHM_W PAGE_READWRITE
#define SHM_RDONLY FILE_MAP_READ
#define SHM_RND FILE_MAP_WRITE
#define SHM_REMAP FILE_MAP_COPY
const char * tsrm_win32_get_path_sid_key(const char *pathname, size_t pathname_len, size_t *key_len);
TSRM_API void tsrm_win32_startup(void);
TSRM_API void tsrm_win32_shutdown(void);
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, const char *env);
TSRM_API FILE *popen(const char *command, const char *type);
TSRM_API int pclose(FILE *stream);
TSRM_API int tsrm_win32_access(const char *pathname, int mode);
TSRM_API int win32_utime(const char *filename, struct utimbuf *buf);
TSRM_API int shmget(key_t key, size_t size, int flags);
TSRM_API void *shmat(int key, const void *shmaddr, int flags);
TSRM_API int shmdt(const void *shmaddr);
TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf);
#endif
-444
View File
@@ -1,444 +0,0 @@
PHP 8.1 UPGRADE NOTES
1. Backward Incompatible Changes
2. New Features
3. Changes in SAPI modules
4. Deprecated Functionality
5. Changed Functions
6. New Functions
7. New Classes and Interfaces
8. Removed Extensions and SAPIs
9. Other Changes to Extensions
10. New Global Constants
11. Changes to INI File Handling
12. Windows Support
13. Other Changes
14. Performance Improvements
========================================
1. Backward Incompatible Changes
========================================
- Core:
. Access to the $GLOBALS array is now subject to a number of restrictions.
Read and write access to individual array elements like $GLOBALS['var']
continues to work as-is. Read-only access to the entire $GLOBALS array also
continues to be supported. However, write access to the entire $GLOBALS
array is no longer supported. For example, array_pop($GLOBALS) will result
in an error.
RFC: https://wiki.php.net/rfc/restrict_globals_usage
. Passing null to a non-nullable argument of a built-in function is
deprecated. This matches the behavior of user-defined functions, where null
is never accepted by non-nullable arguments.
user-defined functions.
var_dump(str_contains("foobar", null));
// Deprecated: Passing null to parameter #2 ($needle) of type string
// is deprecated
RFC: https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg
. When a method using static variables is inherited (but not overridden), the
inherited method will now share static variables with the parent method.
class A {
public static function counter() {
static $counter = 0;
$counter++;
return $counter;
}
}
class B extends A {}
var_dump(A::counter()); // int(1)
var_dump(A::counter()); // int(2)
var_dump(B::counter()); // int(3), previously int(1)
var_dump(B::counter()); // int(4), previously int(2)
This means that static variables in methods now behave the same way as
static properties.
RFC: https://wiki.php.net/rfc/static_variable_inheritance
. Most non-final internal methods now require overriding methods to declare a
compatible return type, otherwise a deprecated notice is emitted during
inheritance validation.
RFC: https://wiki.php.net/rfc/internal_method_return_types
- Fileinfo:
. The fileinfo functions now accept and return, respectively, finfo objects
instead of resources.
- FTP:
. The FTP functions now accept and return, respectively, FTP\Connection objects
instead of resources.
- IMAP:
. The IMAP functions now accept and return, respectively, IMAP\Connection objects
instead of resources.
- LDAP:
. The LDAP functions now accept and return, respectively, LDAP\Connection objects
instead of "ldap link" resources. Return value checks using is_resource()
should be replaced with checks for `false`.
. The LDAP functions now accept and return, respectively, LDAP\Result objects
instead of "ldap result" resources. Return value checks using is_resource()
should be replaced with checks for `false`.
. The LDAP functions now accept and return, respectively, LDAP\ResultEntry
objects instead of "ldap result entry" resources. Return value checks using
is_resource() should be replaced with checks for `false`.
- MySQLi:
. mysqli_fetch_fields() and mysqli_fetch_field_direct() will now always return
zero for max_length. You can compute this information by iterating over the
result set and taking the maximum length. This is what PHP was doing
internally previously.
. The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect.
. The MYSQLI_STORE_RESULT_COPY_DATA option no longer has an effect.
. The default error handling mode has been changed from "silent" to
"exceptions". See https://www.php.net/manual/en/mysqli-driver.report-mode.php
for details of behavior changes and how to explicitly set this attribute. To
keep the old behavior, use mysqli_report(MYSQLI_REPORT_OFF);
RFC: https://wiki.php.net/rfc/mysqli_default_errmode
. Classes extending mysqli_stmt::execute() will be required to specify the
additional parameter now.
RFC: https://wiki.php.net/rfc/mysqli_bind_in_execute
. mysqli::connect() will now return true instead of null on success.
- MySQLnd:
. The mysqlnd.fetch_copy_data ini setting has been removed. However, this
should not result in user-visible behavior changes.
- PDO:
. PDO::ATTR_STRINGIFY_FETCHES now also stringifies values of type bool to
"0" or "1". Previously booleans were not stringified.
. Calling bindColumn() with PDO::PARAM_LOB (and assuming stringification is
not enabled) will now consistently bind a stream result, as documented.
Previously the result would be either a stream or a string depending on the
used database driver and the time the binding is performed.
- PDO MySQL:
. Integers and floats in result sets will now be returned using native PHP
types instead of strings when using emulated prepared statements. This
matches the behavior of native prepared statements. You can restore the
previous behavior by enabling the PDO::ATTR_STRINGIFY_FETCHES option.
- PDO SQLite:
. Integers and floats in results sets will now be returned using native PHP
types. You can restore the previous behavior by enabling the
PDO::ATTR_STRINGIFY_FETCHES option.
- PgSQL:
. The PgSQL functions now accept and return, respectively, \PgSql\Connection
objects instead of "pgsql link" resources. Return value checks using
is_resource() should be replaced with checks for `false`.
. The PgSQL functions now accept and return, respectively, \PgSql\Result
objects instead of "pgsql result" resources. Return value checks using
is_resource() should be replaced with checks for `false`.
. The PgSQL functions now accept and return, respectively, \PgSql\Lob
objects instead of "pgsql large object" resources. Return value checks
using is_resource() should be replaced with checks for `false`.
- PSpell:
. The PSpell functions now accept and return, respectively, PSpell\Dictionary objects
instead of "pspell" resources. Return value checks using is_resource()
should be replaced with checks for `false`.
. The PSpell functions now accept and return, respectively, PSpell\Config objects
instead of "pspell config" resources. Return value checks using is_resource()
should be replaced with checks for `false`.
- Standard:
. version_compare() no longer accepts undocumented operator abbreviations.
. htmlspecialchars(), htmlentities(), htmlspecialchars_decode(),
html_entity_decode() and get_html_translation_table() now use
ENT_QUOTES | ENT_SUBSTITUTE rather than ENT_COMPAT by default. This means
that ' is escaped to &#039; while previously it was left alone.
Additionally, malformed UTF-8 will be replaced by a Unicode substitution
character, instead of resulting in an empty string.
. debug_zval_dump() will now print reference wrappers with their refcount,
instead of only prepending a "&" to the value. This more accurately models
reference representation since PHP 7.0.
. debug_zval_dump() will not print "interned" instead of a dummy refcount of
one for interned strings and immutable arrays.
. fputcsv() now accepts a new "eol" argument which allow to define a custom
eol sequence, the default remains the same and is "\n".
- SPL:
. SplFileObject::fputcsv() now accepts a new "eol" argument which allow to
define a custom eol sequence, the default remains the same and is "\n".
========================================
2. New Features
========================================
- Core:
. It is now possible to specify octal integer by using the explicit "0o"/"0O"
prefix similar to hexadecimal ("0x"/"0X) and binary ("0b"/"0B") integer
literals.
RFC: https://wiki.php.net/rfc/explicit_octal_notation
. Added support for array unpacking with strings keys.
RFC: https://wiki.php.net/rfc/array_unpacking_string_keys
. Added support for enumerations.
RFC: https://wiki.php.net/rfc/enumerations
. Added support for never return type
RFC: https://wiki.php.net/rfc/noreturn_type
. Added support for fibers.
RFC: https://wiki.php.net/rfc/fibers
. File uploads now provide an additional full_path key, which contains the
full path (rather than just the basename) of the uploaded file. This is
intended for use in conjunction with "upload webkitdirectory".
- Curl:
. Added CURLOPT_DOH_URL option.
. Added CURLStringFile, which can be used to post a file from a string rather
than a file:
$file = new CURLStringFile($data, 'filename.txt', 'text/plain');
curl_setopt($curl, CURLOPT_POSTFIELDS, ['file' => $file]);
- FPM:
. Added openmetrics status format. It can be used by Prometheus to fetch FPM
metrics.
. Added new pool option for the dynamic process manager called
pm.max_spawn_rate. It allows to start number of children in a faster rate
when dynamic pm is selected. The default value is 32 which was the previous
hard coded value.
- hash:
. The following functions have changed signatures:
- function hash(string $algo, string $data, bool $binary = false, array $options = []): string|false {}
- function hash_file(string $algo, string $filename, bool $binary = false, array $options = []): string|false {}
- function hash_init(string $algo, int $flags = 0, string $key = "", array $options = []): HashContext {}
The additional `$options` argument can be used to pass algorithm specific data.
. Added MurmurHash3 with streaming support. The following variants are implemented:
- murmur3a, 32-bit hash
- murmur3c, 128-bit hash for x86
- murmur3f, 128-bit hash for x64
The initial hash state can be passed through the `seed` key in the `$options` array, for example:
```php
$h = hash("murmur3f", $data, options: ["seed" => 42]);
echo $h, "\n";
```
A valid seed value is within the range from 0 to the platform defined UINT_MAX, usually 4294967295.
. Added xxHash. The implementation brings in the following arguments
- xxh32, 32-bit hash
- xxh64, 64-bit hash
- xxh3, 64-bit hash
- xxh128, 128-bit hash
The initial hash state can be passed through the `seed` key in the `$options` array, for example:
```php
$h = hash("xxh3", $data, options: ["seed" => 42]);
echo $h, "\n";
```
Secret usage is supported through passing the `secret` key in the `$options` array, too:
```php
$h = hash("xxh3", $data, options: ["secret" => "at least 136 bytes long secret here"]);
echo $h, "\n";
```
Note, that the quality of the custom secret is crucial for the quality of the resulting hash. It is
highly recommended for the secret to use the best possible entropy.
- MySQLi:
. The mysqli.local_infile_directory ini setting has been added, which can be
used to specify a directory from which files are allowed to be loaded. It
is only meaningful if mysqli.allow_local_infile is not enabled, as all
directories are allowed in that case.
. Binding in execute has been added to mysqli prepared statements.
Parameters can now be passed to mysqli_stmt::execute as an array.
RFC: https://wiki.php.net/rfc/mysqli_bind_in_execute
. A new function has been added to mysqli_result called mysqli_fetch_column().
It allows for fetching single scalar values from the result set.
RFC: https://wiki.php.net/rfc/mysqli_fetch_column
- PDO MySQL:
. The PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY attribute has been added, which
can be used to specify a directory from which files are allowed to be
loaded. It is only meaningful if PDO::MYSQL_ATTR_LOCAL_INFILE is not
enabled, as all directories are allowed in that case.
- PDO SQLite:
. SQLite's "file:" DSN syntax is now supported, which allows specifying
additional flags. This feature is not available if open_basedir is set.
Example:
new PDO('sqlite:file:path/to/sqlite.db?mode=ro')
- Posix:
. Added POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS. These rlimits are only
available on FreeBSD.
========================================
3. Changes in SAPI modules
========================================
- CLI:
. Using -a without the readline extension will now result in an error.
Previously, -a without readline had the same behavior as calling php without
any arguments, apart from printing an additional "Interactive mode enabled"
message. This mode was not, in fact, interactive.
========================================
4. Deprecated Functionality
========================================
- Core:
. Implementing the Serializable interface without also implementing
__serialize() and __unserialize() has been deprecated. You should either
implement the new methods (if you only support PHP 7.4 and higher) or
implement both (if you support older PHP versions as well).
RFC: https://wiki.php.net/rfc/phase_out_serializable
- MySQLi:
. The mysqli_driver::$driver_version property has been deprecated. The driver
version is meaningless as it hasn't been updated in more than a decade. Use
PHP_VERSION_ID instead.
. Calling mysqli::get_client_info in OO style or passing $mysqli argument to
mysqli_get_client_info() function has been deprecated. Use
mysqli_get_client_info() without any arguments to obtain the client
library version information.
- PDO:
. The PDO::FETCH_SERIALIZE mode has been deprecated.
RFC: https://wiki.php.net/rfc/phase_out_serializable
========================================
5. Changed Functions
========================================
- Core:
. Properties order used in foreach, var_dump(), serialize(), object comparison
etc. was changed. Now properties are naturally ordered according to their
declaration and inheritance. Properties declared in a base class are going
to be before the child properties. This order is consistent with internal
layout of properties in zend_object structure and repeats the order in
default_properties_table[] and properties_info_table[]. The old order was
not documented and was caused by class inheritance implementation details.
- Filter:
. The FILTER_FLAG_ALLOW_OCTAL flag of the FILTER_VALIDATE_INT filter now accept
octal string with the leading octal prefix ("0o"/"0O")
RFC: https://wiki.php.net/rfc/explicit_octal_notation
- GMP:
. All GMP function now accept octal string with the leading octal prefix ("0o"/"0O")
RFC: https://wiki.php.net/rfc/explicit_octal_notation
- PDO ODBC:
. PDO::getAttributes() with PDO::ATTR_SERVER_INFO and PDO::ATTR_SERVER_VERSION
now return values instead of throwing PDOException.
========================================
6. New Functions
========================================
- Core:
. Added array_is_list(array $array), which will return true if the array keys are 0 .. count($array)-1 in that order.
RFC: https://wiki.php.net/rfc/is_list
- pcntl:
. Added pcntl_rfork for FreeBSD variants
- Reflection:
. Added ReflectionFunctionAbstract::getClosureUsedVariables
- Standard:
. Added fsync() and fdatasync(), which instruct the operating system to
flush its buffers to physical storage.
RFC: https://wiki.php.net/rfc/fsync_function
- Sodium:
. Added the XChaCha20 stream cipher interface functions:
- sodium_crypto_stream_xchacha20()
- sodium_crypto_stream_xchacha20_keygen()
- sodium_crypto_stream_xchacha20_xor()
. Added the Ristretto255 functions, which are available in libsodium 1.0.18.
Ristretto is a technique for constructing prime order elliptic curve groups with non-malleable encodings.
Ristretto255 implements Ristretto atop Curve25519.
- sodium_crypto_core_ristretto255_add()
- sodium_crypto_core_ristretto255_from_hash()
- sodium_crypto_core_ristretto255_is_valid_point()
- sodium_crypto_core_ristretto255_random()
- sodium_crypto_core_ristretto255_scalar_add()
- sodium_crypto_core_ristretto255_scalar_complement()
- sodium_crypto_core_ristretto255_scalar_invert()
- sodium_crypto_core_ristretto255_scalar_mul()
- sodium_crypto_core_ristretto255_scalar_negate()
- sodium_crypto_core_ristretto255_scalar_random()
- sodium_crypto_core_ristretto255_scalar_reduce()
- sodium_crypto_core_ristretto255_scalar_sub()
- sodium_crypto_core_ristretto255_sub()
- sodium_crypto_scalarmult_ristretto255()
- sodium_crypto_scalarmult_ristretto255_base()
========================================
7. New Classes and Interfaces
========================================
========================================
8. Removed Extensions and SAPIs
========================================
========================================
9. Other Changes to Extensions
========================================
- MySQLi:
. The mysqli_stmt::next_result() and mysqli::fetch_all() methods are now
available when linking against libmysqlclient.
- OpenSSL:
. The OpenSSL extension now requires at least OpenSSL version 1.0.2.
- Sockets:
. FreeBSD defines SO_ACCEPTFILTER
- Standard:
. --with-password-argon2 now uses pkg-config to detect libargon2. As such,
an alternative libargon2 location should now be specified using
PKG_CONFIG_PATH.
========================================
10. New Global Constants
========================================
- MySQLi:
. MYSQLI_REFRESH_REPLICA has been added as a replacement for
MYSQLI_REFRESH_SLAVE, in line with an upstream change in MySQL. The old
constant is still available for backwards-compatibility reasons, but may
be deprecated/removed in the future.
========================================
11. Changes to INI File Handling
========================================
- The log_errors_max_len ini setting has been removed. It no longer had an
effect since PHP 8.0.
========================================
12. Windows Support
========================================
. The macro IGNORE_URL_WIN has been removed; it had no effect as of PHP 5.0.0.
========================================
13. Other Changes
========================================
========================================
14. Performance Improvements
========================================
-110
View File
@@ -1,110 +0,0 @@
PHP 8.1 INTERNALS UPGRADE NOTES
1. Internal API changes
a. Removed Zend APIs
b. Zend Stream API
c. zend_get_opcode_id()
2. Build system changes
a. New compiler flags
3. Module changes
a. ext/hash
b. ext/pdo
c. ext/standard
d. ext/pgsql
e. ext/pcre
========================
1. Internal API changes
========================
a. The following APIs have been removed from the Zend Engine:
- The spl_ce_Aggregate, spl_ce_ArrayAccess, spl_ce_Countable, spl_ce_Iterator, spl_ce_Serializable,
spl_ce_Stringable, spl_ce_Traversable alias class entries have been removed in favor of zend_ce_aggregate,
zend_ce_arrayaccess, zend_ce_countable, zend_ce_iterator, zend_ce_serializable, zend_ce_stringable,
zend_ce_traversable.
b. Zend Stream API has been changed to use "zend_string*" instead of "char*"
- zend_file_handle.filename now is zend_string*
- zend_file_handle.free_filename is removed. Now zend_file_handle.filename is always released.
- added zend_file_handle.primary_script flag. SAPIs should set it for main executed script.
- added zend_file_handle.in_list flag, which is set when a file_handle is added into CG(open_files)
- added zend_stream_init_filename_ex() function, that takes filename as zend_string*
- the "filename" parameter of functons zend_stream_open(), php_stream_open_for_zend_ex() and
callback zend_stream_open_function() has been removed (it's now passed as a "filename" field of the
file_handle parameter)
- in zend_fopen() and zend_resolve_path() callbacks filename now passed as zend_string*
- file_handles should be destroyed by zend_destroy_file_handle() function (usually in the same function
the same function where they were created by zend_stream_init_*()). Previously there were two different
destructors zend_destroy_file_handle() and zend_file_handle_dtor().
- zend_ini_scanner_globals.filename now is zend_string*
c. Added the zend_get_opcode_id() function, which is intended to get opcode id from name.
========================
2. Build system changes
========================
a. New compiler flags
- [-Wimplicit-fallthrough=1] is now enabled by default.
It is possible to use the new ZEND_FALLTHROUGH macro keyword to suppress the warning.
========================
3. Module changes
========================
a. ext/hash
- The init signatures are extended with an additional `HashTable*`
argument. The passed HT is to contain the algorithm specific
configuration. If an algorithm doesn't make use of any additional
configuration, the argument is to be marked with ZEND_ATTRIBUTE_UNUSED.
b. ext/pdo
- The "preparer" callback now accepts a zend_string* instead of
char* + size_t pair the query string. Similarly, the query_string and
active_query_string members of pdo_stmt_t are now zend_string*.
- The way in which drivers provide results has changed: Previously,
the "describer" callback populated the "pdo_type" member in the
pdo_column_data structure, and the "get_col" callback then had to return
pointers to data of appropriate type.
In PHP 8.1, the "describer" callback no longer determines the pdo_type
(and this member has been removed from pdo_column_data). Instead, the
"get_col" callback accepts a zval pointer that may be populated with a
value of arbitrary type. This gives drivers more flexibility in
determining result types (e.g. based on whether a specific integer fits
the PHP integer type) and avoid awkward juggling of temporary buffers.
As the "describer" no longer determines pdo_type, the "get_column_meta"
function is now responsible for providing this information for use by
getColumnMeta(). The type provided here does not need to match the type
returned by get_col (in fact no corresponding type might exist, e.g. for
floats). It should be the closest logical equivalent for the column type.
- The transaction, set_attribute, and preparer handler's return type
has been formalized to bool instead of int.
- The check_liveness handler's return type has been formalized to zend_return
instead of int.
- The closer, and fetch_error handlers have been voidified.
- The quoter handler now returns the quoted string as zend_string* instead
of returning a boolean, and the quoted string as a pair of out params.
Similarly the unquoted string is now a zend_string* instead of a pair of
char* and size_t length.
- The doer handler now accepts a zend_string* instead of char* + size_t
pair for the SQL statement.
- The last_id handler now returns a zend_string* instead of returning a
char* and the length as an out param, and accepts a zend_string* instead
of char* for the optional sequence/table name.
- The php_pdo_str_tolower_dup() PDO_API has been removed use zend_str_tolower_dup()
or zend_string_tolower_ex().
c. ext/standard
- The PHP API php_fputcsv() now takes an extra zend_string* argument at the end
for a custom EOL sequence, passing NULL provides the old default of "\n".
d. ext/pgsql
- The functions php_pgsql_meta_data(), php_pgsql_convert(), php_pgsql_insert(),
php_pgsql_update(), php_pgsql_delete(), and php_pgsql_select() have had
their return type formalized to zend_result.
- The functions php_pgsql_meta_data(), php_pgsql_convert(), php_pgsql_insert(),
php_pgsql_update(), php_pgsql_delete(), and php_pgsql_select() now accept a
zend_string* instead of a char* for the table name.
e. ext/pcre
- Bundled PCRE2 is at version 10.37. The most important diff to the previous
version is the JIT support on the S390 platform.
-56
View File
@@ -1,56 +0,0 @@
--------------------------------------------------------------------
The Zend Engine License, Version 2.00
Copyright (c) 1999-2006 Zend Technologies Ltd. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
3. The names "Zend" and "Zend Engine" must not be used to endorse
or promote products derived from this software without prior
permission from Zend Technologies Ltd. For written permission,
please contact license@zend.com.
4. Zend Technologies Ltd. may publish revised and/or new versions
of the license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the
terms of that version. You may also choose to use such covered
code under the terms of any subsequent version of the license
published by Zend Technologies Ltd. No one other than Zend
Technologies Ltd. has the right to modify the terms applicable
to covered code created under this License.
5. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes the Zend Engine, freely available at
http://www.zend.com"
6. All advertising materials mentioning features or use of this
software must display the following acknowledgment:
"The Zend Engine is freely available at http://www.zend.com"
THIS SOFTWARE IS PROVIDED BY ZEND TECHNOLOGIES LTD. ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ZEND
TECHNOLOGIES LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
--------------------------------------------------------------------
-42
View File
@@ -1,42 +0,0 @@
#
# Zend
#
$(builddir)/zend_language_scanner.lo: $(srcdir)/zend_language_parser.h
$(builddir)/zend_ini_scanner.lo: $(srcdir)/zend_ini_parser.h
$(srcdir)/zend_language_scanner.c: $(srcdir)/zend_language_scanner.l
@(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date --case-inverted -cbdFt Zend/zend_language_scanner_defs.h -oZend/zend_language_scanner.c Zend/zend_language_scanner.l)
$(srcdir)/zend_language_parser.h: $(srcdir)/zend_language_parser.c
$(srcdir)/zend_language_parser.c: $(srcdir)/zend_language_parser.y
# Tweak zendparse to be exported through ZEND_API. This has to be revisited once
# bison supports foreign skeletons and that bison version is used. Read
# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more.
@$(YACC) $(YFLAGS) -v -d $(srcdir)/zend_language_parser.y -o $@
@$(SED) -e 's,^int zendparse\(.*\),ZEND_API int zendparse\1,g' < $@ \
> $@.tmp && \
mv $@.tmp $@
@$(SED) -e 's,^int zendparse\(.*\),ZEND_API int zendparse\1,g' < $(srcdir)/zend_language_parser.h \
> $(srcdir)/zend_language_parser.h.tmp && \
mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
@nlinit=`echo 'nl="'; echo '"'`; eval "$$nlinit"; \
$(SED) -e "s/^#ifndef YYTOKENTYPE/#include \"zend.h\"\\$${nl}#ifndef YYTOKENTYPE/" < $(srcdir)/zend_language_parser.h \
> $(srcdir)/zend_language_parser.h.tmp && \
mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
$(srcdir)/zend_ini_parser.h: $(srcdir)/zend_ini_parser.c
$(srcdir)/zend_ini_parser.c: $(srcdir)/zend_ini_parser.y
$(YACC) $(YFLAGS) -v -d $(srcdir)/zend_ini_parser.y -o $@
$(srcdir)/zend_ini_scanner.c: $(srcdir)/zend_ini_scanner.l
@(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date --case-inverted -cbdFt Zend/zend_ini_scanner_defs.h -oZend/zend_ini_scanner.c Zend/zend_ini_scanner.l)
$(srcdir)/zend_vm_execute.h $(srcdir)/zend_vm_opcodes.c: $(srcdir)/zend_vm_def.h $(srcdir)/zend_vm_execute.skl $(srcdir)/zend_vm_gen.php
@if test ! -z "$(PHP)"; then \
$(PHP) $(srcdir)/zend_vm_gen.php; \
fi;
$(builddir)/zend_highlight.lo $(builddir)/zend_compile.lo: $(srcdir)/zend_language_parser.h
Zend/zend_execute.lo: $(srcdir)/zend_vm_execute.h $(srcdir)/zend_vm_opcodes.h
File diff suppressed because it is too large. Load diff
-864
View File
@@ -1,864 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
| Xinchen Hui <laruence@php.net> |
+----------------------------------------------------------------------+
*/
/* pass 11
* - compact literals table
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
#include "zend_extensions.h"
#define DEBUG_COMPACT_LITERALS 0
#define LITERAL_VALUE 0x0100
#define LITERAL_FUNC 0x0200
#define LITERAL_CLASS 0x0300
#define LITERAL_CONST 0x0400
#define LITERAL_CLASS_CONST 0x0500
#define LITERAL_STATIC_METHOD 0x0600
#define LITERAL_STATIC_PROPERTY 0x0700
#define LITERAL_METHOD 0x0800
#define LITERAL_PROPERTY 0x0900
#define LITERAL_GLOBAL 0x0A00
#define LITERAL_KIND_MASK 0x0f00
#define LITERAL_NUM_RELATED_MASK 0x000f
#define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK)
typedef struct _literal_info {
uint32_t flags; /* bitmask (see defines above) */
} literal_info;
#define LITERAL_INFO(n, kind, related) do { \
info[n].flags = ((kind) | (related)); \
} while (0)
static size_t type_num_classes(const zend_op_array *op_array, uint32_t arg_num)
{
zend_arg_info *arg_info;
if (arg_num > 0) {
if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
return 0;
}
if (EXPECTED(arg_num <= op_array->num_args)) {
arg_info = &op_array->arg_info[arg_num-1];
} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
arg_info = &op_array->arg_info[op_array->num_args];
} else {
return 0;
}
} else {
arg_info = op_array->arg_info - 1;
}
if (ZEND_TYPE_HAS_CLASS(arg_info->type)) {
if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
return ZEND_TYPE_LIST(arg_info->type)->num_types;
}
return 1;
}
return 0;
}
static uint32_t add_static_slot(HashTable *hash,
zend_op_array *op_array,
uint32_t op1,
uint32_t op2,
uint32_t kind,
int *cache_size)
{
uint32_t ret;
zval *class_name = &op_array->literals[op1];
zval *prop_name = &op_array->literals[op2];
zval *pos, tmp;
zend_string *key = zend_create_member_string(Z_STR_P(class_name), Z_STR_P(prop_name));
ZSTR_H(key) = zend_string_hash_func(key);
ZSTR_H(key) += kind;
pos = zend_hash_find(hash, key);
if (pos) {
ret = Z_LVAL_P(pos);
} else {
ret = *cache_size;
*cache_size += (kind == LITERAL_STATIC_PROPERTY ? 3 : 2) * sizeof(void *);
ZVAL_LONG(&tmp, ret);
zend_hash_add(hash, key, &tmp);
}
zend_string_release_ex(key, 0);
return ret;
}
static zend_string *create_str_cache_key(zval *literal, uint32_t flags)
{
ZEND_ASSERT(Z_TYPE_P(literal) == IS_STRING);
uint32_t num_related = LITERAL_NUM_RELATED(flags);
if (num_related == 1) {
return zend_string_copy(Z_STR_P(literal));
}
if ((flags & LITERAL_KIND_MASK) == LITERAL_VALUE) {
/* Don't merge LITERAL_VALUE that has related literals */
return NULL;
}
/* Concatenate all the related literals for the cache key. */
zend_string *key;
if (num_related == 2) {
ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING);
key = zend_string_concat2(
Z_STRVAL_P(literal), Z_STRLEN_P(literal),
Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1));
} else if (num_related == 3) {
ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING && Z_TYPE_P(literal + 2) == IS_STRING);
key = zend_string_concat3(
Z_STRVAL_P(literal), Z_STRLEN_P(literal),
Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1),
Z_STRVAL_P(literal + 2), Z_STRLEN_P(literal + 2));
} else {
ZEND_ASSERT(0 && "Currently not needed");
}
/* Add a bias to the hash so we can distinguish keys
* that would otherwise be the same after concatenation. */
ZSTR_H(key) = zend_string_hash_val(key) + num_related - 1;
return key;
}
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline, *end;
int i, j, n, *map, cache_size;
zval zv, *pos;
literal_info *info;
int l_null = -1;
int l_false = -1;
int l_true = -1;
int l_empty_arr = -1;
HashTable hash, double_hash;
zend_string *key = NULL;
void *checkpoint = zend_arena_checkpoint(ctx->arena);
int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
if (op_array->last_literal) {
info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
/* Mark literals of specific types */
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
switch (opline->opcode) {
case ZEND_INIT_FCALL:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1);
break;
case ZEND_INIT_FCALL_BY_NAME:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 2);
break;
case ZEND_INIT_NS_FCALL_BY_NAME:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 3);
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_METHOD, 2);
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_STATIC_METHOD, 2);
}
break;
case ZEND_CATCH:
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
break;
case ZEND_DEFINED:
LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1);
break;
case ZEND_FETCH_CONSTANT:
if (opline->op1.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3);
} else {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 2);
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS_CONST, 1);
break;
case ZEND_ASSIGN_STATIC_PROP:
case ZEND_ASSIGN_STATIC_PROP_REF:
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW:
case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
case ZEND_PRE_INC_STATIC_PROP:
case ZEND_PRE_DEC_STATIC_PROP:
case ZEND_POST_INC_STATIC_PROP:
case ZEND_POST_DEC_STATIC_PROP:
case ZEND_ASSIGN_STATIC_PROP_OP:
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
}
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_STATIC_PROPERTY, 1);
}
break;
case ZEND_FETCH_CLASS:
case ZEND_INSTANCEOF:
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
}
break;
case ZEND_NEW:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
break;
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_REF:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_RW:
case ZEND_FETCH_OBJ_IS:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_UNSET_OBJ:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
case ZEND_ASSIGN_OBJ_OP:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1);
}
break;
case ZEND_BIND_GLOBAL:
LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 1);
break;
case ZEND_RECV_INIT:
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
break;
case ZEND_DECLARE_CLASS:
case ZEND_DECLARE_CLASS_DELAYED:
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
}
break;
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ASSIGN_DIM:
case ZEND_UNSET_DIM:
case ZEND_FETCH_DIM_R:
case ZEND_FETCH_DIM_W:
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_IS:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
case ZEND_FETCH_LIST_R:
case ZEND_FETCH_LIST_W:
case ZEND_ASSIGN_DIM_OP:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
if (Z_EXTRA(op_array->literals[opline->op2.constant]) == ZEND_EXTRA_VALUE) {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 2);
} else {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
}
}
break;
default:
if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
}
break;
}
opline++;
}
#if DEBUG_COMPACT_LITERALS
{
int i, use_copy;
fprintf(stderr, "File %s func %s\n", op_array->filename->val,
op_array->function_name ? op_array->function_name->val : "main");
fprintf(stderr, "Literals table size %d\n", op_array->last_literal);
for (i = 0; i < op_array->last_literal; i++) {
zval zv;
ZVAL_COPY_VALUE(&zv, op_array->literals + i);
use_copy = zend_make_printable_zval(op_array->literals + i, &zv);
fprintf(stderr, "Literal %d, val (%zu):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
if (use_copy) {
zval_ptr_dtor_nogc(&zv);
}
}
fflush(stderr);
}
#endif
/* Merge equal constants */
j = 0;
zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
/* Use separate hashtable for doubles stored as string keys, to avoid collisions. */
zend_hash_init(&double_hash, 0, NULL, NULL, 0);
map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
memset(map, 0, op_array->last_literal * sizeof(int));
for (i = 0; i < op_array->last_literal; i++) {
if (!info[i].flags) {
/* unset literal */
zval_ptr_dtor_nogc(&op_array->literals[i]);
continue;
}
switch (Z_TYPE(op_array->literals[i])) {
case IS_NULL:
if (l_null < 0) {
l_null = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
map[i] = l_null;
break;
case IS_FALSE:
if (l_false < 0) {
l_false = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
map[i] = l_false;
break;
case IS_TRUE:
if (l_true < 0) {
l_true = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
map[i] = l_true;
break;
case IS_LONG:
if (LITERAL_NUM_RELATED(info[i].flags) == 1) {
if ((pos = zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i]))) != NULL) {
map[i] = Z_LVAL_P(pos);
} else {
map[i] = j;
ZVAL_LONG(&zv, j);
zend_hash_index_add_new(&hash, Z_LVAL(op_array->literals[i]), &zv);
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
} else {
ZEND_ASSERT(LITERAL_NUM_RELATED(info[i].flags) == 2);
key = zend_string_init(Z_STRVAL(op_array->literals[i+1]), Z_STRLEN(op_array->literals[i+1]), 0);
ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i+1])) + 100 +
LITERAL_NUM_RELATED(info[i].flags) - 1;
if ((pos = zend_hash_find(&hash, key)) != NULL
&& LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) == 2) {
map[i] = Z_LVAL_P(pos);
zval_ptr_dtor_nogc(&op_array->literals[i+1]);
} else {
map[i] = j;
ZVAL_LONG(&zv, j);
zend_hash_add_new(&hash, key, &zv);
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
op_array->literals[j+1] = op_array->literals[i+1];
info[j+1] = info[i+1];
}
j += 2;
}
zend_string_release_ex(key, 0);
i++;
}
break;
case IS_DOUBLE:
if ((pos = zend_hash_str_find(&double_hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double))) != NULL) {
map[i] = Z_LVAL_P(pos);
} else {
map[i] = j;
ZVAL_LONG(&zv, j);
zend_hash_str_add_new(&double_hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double), &zv);
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
break;
case IS_STRING: {
key = create_str_cache_key(&op_array->literals[i], info[i].flags);
if (key && (pos = zend_hash_find(&hash, key)) != NULL &&
Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING &&
LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) &&
(LITERAL_NUM_RELATED(info[i].flags) != 2 ||
((info[i].flags & LITERAL_KIND_MASK) != LITERAL_VALUE &&
(info[Z_LVAL_P(pos)].flags & LITERAL_KIND_MASK) != LITERAL_VALUE))) {
zend_string_release_ex(key, 0);
map[i] = Z_LVAL_P(pos);
zval_ptr_dtor_nogc(&op_array->literals[i]);
n = LITERAL_NUM_RELATED(info[i].flags);
while (n > 1) {
i++;
zval_ptr_dtor_nogc(&op_array->literals[i]);
n--;
}
} else {
map[i] = j;
ZVAL_LONG(&zv, j);
if (key) {
zend_hash_add_new(&hash, key, &zv);
zend_string_release_ex(key, 0);
}
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
n = LITERAL_NUM_RELATED(info[i].flags);
while (n > 1) {
i++;
if (i != j) op_array->literals[j] = op_array->literals[i];
j++;
n--;
}
}
break;
}
case IS_ARRAY:
if (zend_hash_num_elements(Z_ARRVAL(op_array->literals[i])) == 0) {
if (l_empty_arr < 0) {
l_empty_arr = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
} else {
zval_ptr_dtor_nogc(&op_array->literals[i]);
}
map[i] = l_empty_arr;
break;
}
ZEND_FALLTHROUGH;
default:
/* don't merge other types */
map[i] = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
break;
}
}
/* Only clean "hash", as it will be reused in the loop below. */
zend_hash_clean(&hash);
zend_hash_destroy(&double_hash);
op_array->last_literal = j;
const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
memset(const_slot, -1, j * 6 * sizeof(int));
class_slot = const_slot + j;
func_slot = class_slot + j;
bind_var_slot = func_slot + j;
property_slot = bind_var_slot + j;
method_slot = property_slot + j;
/* Update opcodes to use new literals table */
cache_size = zend_op_array_extension_handles * sizeof(void*);
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
if (opline->op1_type == IS_CONST) {
opline->op1.constant = map[opline->op1.constant];
}
if (opline->op2_type == IS_CONST) {
opline->op2.constant = map[opline->op2.constant];
}
switch (opline->opcode) {
case ZEND_RECV_INIT:
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
{
size_t num_classes = type_num_classes(op_array, opline->op1.num);
if (num_classes) {
opline->extended_value = cache_size;
cache_size += num_classes * sizeof(void *);
}
break;
}
case ZEND_VERIFY_RETURN_TYPE:
{
size_t num_classes = type_num_classes(op_array, 0);
if (num_classes) {
opline->op2.num = cache_size;
cache_size += num_classes * sizeof(void *);
}
break;
}
case ZEND_ASSIGN_STATIC_PROP_OP:
if (opline->op1_type == IS_CONST) {
// op1 static property
if (opline->op2_type == IS_CONST) {
(opline+1)->extended_value = add_static_slot(&hash, op_array,
opline->op2.constant,
opline->op1.constant,
LITERAL_STATIC_PROPERTY,
&cache_size);
} else {
(opline+1)->extended_value = cache_size;
cache_size += 3 * sizeof(void *);
}
} else if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
(opline+1)->extended_value = class_slot[opline->op2.constant];
} else {
(opline+1)->extended_value = cache_size;
class_slot[opline->op2.constant] = cache_size;
cache_size += sizeof(void *);
}
}
break;
case ZEND_ASSIGN_OBJ_OP:
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
(opline+1)->extended_value = property_slot[opline->op2.constant];
} else {
(opline+1)->extended_value = cache_size;
cache_size += 3 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = (opline+1)->extended_value;
}
}
}
break;
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_REF:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_RW:
case ZEND_FETCH_OBJ_IS:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_UNSET_OBJ:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
cache_size += 3 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
}
}
}
break;
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY);
cache_size += 3 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY;
}
}
}
break;
case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
// op2 func
if (func_slot[opline->op2.constant] >= 0) {
opline->result.num = func_slot[opline->op2.constant];
} else {
opline->result.num = cache_size;
cache_size += sizeof(void *);
func_slot[opline->op2.constant] = opline->result.num;
}
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op2_type == IS_CONST) {
// op2 method
if (opline->op1_type == IS_UNUSED &&
method_slot[opline->op2.constant] >= 0) {
opline->result.num = method_slot[opline->op2.constant];
} else {
opline->result.num = cache_size;
cache_size += 2 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
method_slot[opline->op2.constant] = opline->result.num;
}
}
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
if (opline->op2_type == IS_CONST) {
// op2 static method
if (opline->op1_type == IS_CONST) {
opline->result.num = add_static_slot(&hash, op_array,
opline->op1.constant,
opline->op2.constant,
LITERAL_STATIC_METHOD,
&cache_size);
} else {
opline->result.num = cache_size;
cache_size += 2 * sizeof(void *);
}
} else if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->result.num = class_slot[opline->op1.constant];
} else {
opline->result.num = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->result.num;
}
}
break;
case ZEND_DEFINED:
// op1 const
if (const_slot[opline->op1.constant] >= 0) {
opline->extended_value = const_slot[opline->op1.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
const_slot[opline->op1.constant] = opline->extended_value;
}
break;
case ZEND_FETCH_CONSTANT:
// op2 const
if (const_slot[opline->op2.constant] >= 0) {
opline->extended_value = const_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
const_slot[opline->op2.constant] = opline->extended_value;
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op1_type == IS_CONST) {
// op1/op2 class_const
opline->extended_value = add_static_slot(&hash, op_array,
opline->op1.constant,
opline->op2.constant,
LITERAL_CLASS_CONST,
&cache_size);
} else {
opline->extended_value = cache_size;
cache_size += 2 * sizeof(void *);
}
break;
case ZEND_ASSIGN_STATIC_PROP:
case ZEND_ASSIGN_STATIC_PROP_REF:
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW:
case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
case ZEND_PRE_INC_STATIC_PROP:
case ZEND_PRE_DEC_STATIC_PROP:
case ZEND_POST_INC_STATIC_PROP:
case ZEND_POST_DEC_STATIC_PROP:
if (opline->op1_type == IS_CONST) {
// op1 static property
if (opline->op2_type == IS_CONST) {
opline->extended_value = add_static_slot(&hash, op_array,
opline->op2.constant,
opline->op1.constant,
LITERAL_STATIC_PROPERTY,
&cache_size) | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
cache_size += 3 * sizeof(void *);
}
} else if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
class_slot[opline->op2.constant] = cache_size;
cache_size += sizeof(void *);
}
}
break;
case ZEND_FETCH_CLASS:
case ZEND_INSTANCEOF:
if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
opline->extended_value = class_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op2.constant] = opline->extended_value;
}
}
break;
case ZEND_NEW:
if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->op2.num = class_slot[opline->op1.constant];
} else {
opline->op2.num = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->op2.num;
}
}
break;
case ZEND_CATCH:
if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->extended_value = class_slot[opline->op1.constant] | (opline->extended_value & ZEND_LAST_CATCH);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_LAST_CATCH);
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->extended_value & ~ZEND_LAST_CATCH;
}
}
break;
case ZEND_BIND_GLOBAL:
// op2 bind var
if (bind_var_slot[opline->op2.constant] >= 0) {
opline->extended_value = bind_var_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
bind_var_slot[opline->op2.constant] = opline->extended_value;
}
break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_CLASS_DELAYED:
opline->extended_value = cache_size;
cache_size += sizeof(void *);
break;
case ZEND_SEND_VAL:
case ZEND_SEND_VAL_EX:
case ZEND_SEND_VAR:
case ZEND_SEND_VAR_EX:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_REF:
case ZEND_SEND_FUNC_ARG:
case ZEND_CHECK_FUNC_ARG:
if (opline->op2_type == IS_CONST) {
opline->result.num = cache_size;
cache_size += 2 * sizeof(void *);
}
break;
}
opline++;
}
op_array->cache_size = cache_size;
zend_hash_destroy(&hash);
zend_arena_release(&ctx->arena, checkpoint);
if (1) {
opline = op_array->opcodes;
while (1) {
if (opline->opcode == ZEND_RECV_INIT) {
zval *val = &op_array->literals[opline->op2.constant];
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
/* Ensure zval is aligned to 8 bytes */
op_array->cache_size = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
Z_CACHE_SLOT_P(val) = op_array->cache_size;
op_array->cache_size += sizeof(zval);
}
} else if (opline->opcode != ZEND_RECV) {
break;
}
opline++;
}
}
#if DEBUG_COMPACT_LITERALS
{
int i, use_copy;
fprintf(stderr, "Optimized literals table size %d\n", op_array->last_literal);
for (i = 0; i < op_array->last_literal; i++) {
zval zv;
ZVAL_COPY_VALUE(&zv, op_array->literals + i);
use_copy = zend_make_printable_zval(op_array->literals + i, &zv);
fprintf(stderr, "Literal %d, val (%zu):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
if (use_copy) {
zval_ptr_dtor_nogc(&zv);
}
}
fflush(stderr);
}
#endif
}
}
-123
View File
@@ -1,123 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Removing unused variables |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Nikita Popov <nikic@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_bitset.h"
/* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs.
* This pass does not operate on SSA form anymore. */
void zend_optimizer_compact_vars(zend_op_array *op_array) {
int i;
ALLOCA_FLAG(use_heap1);
ALLOCA_FLAG(use_heap2);
uint32_t used_vars_len = zend_bitset_len(op_array->last_var + op_array->T);
zend_bitset used_vars = ZEND_BITSET_ALLOCA(used_vars_len, use_heap1);
uint32_t *vars_map = do_alloca((op_array->last_var + op_array->T) * sizeof(uint32_t), use_heap2);
uint32_t num_cvs, num_tmps;
/* Determine which CVs are used */
zend_bitset_clear(used_vars, used_vars_len);
for (i = 0; i < op_array->last; i++) {
zend_op *opline = &op_array->opcodes[i];
if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
zend_bitset_incl(used_vars, VAR_NUM(opline->op1.var));
}
if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
zend_bitset_incl(used_vars, VAR_NUM(opline->op2.var));
}
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
zend_bitset_incl(used_vars, VAR_NUM(opline->result.var));
if (opline->opcode == ZEND_ROPE_INIT) {
uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
while (num > 1) {
num--;
zend_bitset_incl(used_vars, VAR_NUM(opline->result.var) + num);
}
}
}
}
num_cvs = 0;
for (i = 0; i < op_array->last_var; i++) {
if (zend_bitset_in(used_vars, i)) {
vars_map[i] = num_cvs++;
} else {
vars_map[i] = (uint32_t) -1;
}
}
num_tmps = 0;
for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) {
if (zend_bitset_in(used_vars, i)) {
vars_map[i] = num_cvs + num_tmps++;
} else {
vars_map[i] = (uint32_t) -1;
}
}
free_alloca(used_vars, use_heap1);
if (num_cvs == op_array->last_var && num_tmps == op_array->T) {
free_alloca(vars_map, use_heap2);
return;
}
ZEND_ASSERT(num_cvs <= op_array->last_var);
ZEND_ASSERT(num_tmps <= op_array->T);
/* Update CV and TMP references in opcodes */
for (i = 0; i < op_array->last; i++) {
zend_op *opline = &op_array->opcodes[i];
if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
opline->op1.var = NUM_VAR(vars_map[VAR_NUM(opline->op1.var)]);
}
if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
opline->op2.var = NUM_VAR(vars_map[VAR_NUM(opline->op2.var)]);
}
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
opline->result.var = NUM_VAR(vars_map[VAR_NUM(opline->result.var)]);
}
}
/* Update CV name table */
if (num_cvs != op_array->last_var) {
if (num_cvs) {
zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0);
for (i = 0; i < op_array->last_var; i++) {
if (vars_map[i] != (uint32_t) -1) {
names[vars_map[i]] = op_array->vars[i];
} else {
zend_string_release_ex(op_array->vars[i], 0);
}
}
efree(op_array->vars);
op_array->vars = names;
} else {
for (i = 0; i < op_array->last_var; i++) {
zend_string_release_ex(op_array->vars[i], 0);
}
efree(op_array->vars);
op_array->vars = NULL;
}
op_array->last_var = num_cvs;
}
op_array->T = num_tmps;
free_alloca(vars_map, use_heap2);
}
-651
View File
@@ -1,651 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, DCE - Dead Code Elimination |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Nikita Popov <nikic@php.net> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer_internal.h"
#include "Optimizer/zend_inference.h"
#include "Optimizer/zend_ssa.h"
#include "Optimizer/zend_func_info.h"
#include "Optimizer/zend_call_graph.h"
#include "zend_bitset.h"
/* This pass implements a form of dead code elimination (DCE). The algorithm optimistically assumes
* that all instructions and phis are dead. Instructions with immediate side-effects are then marked
* as live. We then recursively (using a worklist) propagate liveness to the instructions that def
* the used operands.
*
* Notes:
* * This pass does not perform unreachable code elimination. This happens as part of the SCCP
* pass.
* * The DCE is performed without taking control-dependence into account, i.e. all conditional
* branches are assumed to be live. It's possible to take control-dependence into account using
* the DCE algorithm described by Cytron et al., however it requires the construction of a
* postdominator tree and of postdominance frontiers, which does not seem worthwhile at this
* point.
* * We separate intrinsic side-effects from potential side-effects in the form of notices thrown
* by the instruction (in case we want to make this configurable). See may_have_side_effects() and
* zend_may_throw().
* * We often cannot DCE assignments and unsets while guaranteeing that dtors run in the same
* order. There is an optimization option to allow reordering of dtor effects.
* * The algorithm is able to eliminate dead modifications of non-escaping arrays
* and objects as well as dead arrays and objects allocations.
*/
typedef struct {
zend_ssa *ssa;
zend_op_array *op_array;
zend_bitset instr_dead;
zend_bitset phi_dead;
zend_bitset instr_worklist;
zend_bitset phi_worklist;
zend_bitset phi_worklist_no_val;
uint32_t instr_worklist_len;
uint32_t phi_worklist_len;
unsigned reorder_dtor_effects : 1;
} context;
static inline bool is_bad_mod(const zend_ssa *ssa, int use, int def) {
if (def < 0) {
/* This modification is not tracked by SSA, assume the worst */
return 1;
}
if (ssa->var_info[use].type & MAY_BE_REF) {
/* Modification of reference may have side-effect */
return 1;
}
return 0;
}
static inline bool may_have_side_effects(
zend_op_array *op_array, zend_ssa *ssa,
const zend_op *opline, const zend_ssa_op *ssa_op,
bool reorder_dtor_effects) {
switch (opline->opcode) {
case ZEND_NOP:
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_QM_ASSIGN:
case ZEND_FREE:
case ZEND_FE_FREE:
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
case ZEND_ADD:
case ZEND_SUB:
case ZEND_MUL:
case ZEND_POW:
case ZEND_BW_OR:
case ZEND_BW_AND:
case ZEND_BW_XOR:
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
case ZEND_DIV:
case ZEND_MOD:
case ZEND_BOOL_XOR:
case ZEND_BOOL:
case ZEND_BOOL_NOT:
case ZEND_BW_NOT:
case ZEND_SL:
case ZEND_SR:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
case ZEND_CASE_STRICT:
case ZEND_CAST:
case ZEND_ROPE_INIT:
case ZEND_ROPE_ADD:
case ZEND_INIT_ARRAY:
case ZEND_ADD_ARRAY_ELEMENT:
case ZEND_SPACESHIP:
case ZEND_STRLEN:
case ZEND_COUNT:
case ZEND_GET_TYPE:
case ZEND_ISSET_ISEMPTY_THIS:
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_FETCH_DIM_IS:
case ZEND_ISSET_ISEMPTY_CV:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_FETCH_IS:
case ZEND_IN_ARRAY:
case ZEND_FUNC_NUM_ARGS:
case ZEND_FUNC_GET_ARGS:
case ZEND_ARRAY_KEY_EXISTS:
/* No side effects */
return 0;
case ZEND_ROPE_END:
/* TODO: Rope dce optimization, see #76446 */
return 1;
case ZEND_JMP:
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
case ZEND_JMP_NULL:
/* For our purposes a jumps and branches are side effects. */
return 1;
case ZEND_BEGIN_SILENCE:
case ZEND_END_SILENCE:
case ZEND_ECHO:
case ZEND_INCLUDE_OR_EVAL:
case ZEND_THROW:
case ZEND_MATCH_ERROR:
case ZEND_EXT_STMT:
case ZEND_EXT_FCALL_BEGIN:
case ZEND_EXT_FCALL_END:
case ZEND_TICKS:
case ZEND_YIELD:
case ZEND_YIELD_FROM:
case ZEND_VERIFY_NEVER_TYPE:
/* Intrinsic side effects */
return 1;
case ZEND_DO_FCALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
/* For now assume all calls have side effects */
return 1;
case ZEND_RECV:
case ZEND_RECV_INIT:
/* Even though RECV_INIT can be side-effect free, these cannot be simply dropped
* due to the prologue skipping code. */
return 1;
case ZEND_ASSIGN_REF:
return 1;
case ZEND_ASSIGN:
{
if (is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)) {
return 1;
}
if (!reorder_dtor_effects) {
if (opline->op2_type != IS_CONST
&& (OP2_INFO() & MAY_HAVE_DTOR)
&& ssa->vars[ssa_op->op2_use].escape_state != ESCAPE_STATE_NO_ESCAPE) {
/* DCE might shorten lifetime */
return 1;
}
}
return 0;
}
case ZEND_UNSET_VAR:
return 1;
case ZEND_UNSET_CV:
{
uint32_t t1 = OP1_INFO();
if (t1 & MAY_BE_REF) {
/* We don't consider uses as the LHS of an assignment as real uses during DCE, so
* an unset may be considered dead even if there is a later assignment to the
* variable. Removing the unset in this case would not be correct if the variable
* is a reference, because unset breaks references. */
return 1;
}
return 0;
}
case ZEND_PRE_INC:
case ZEND_POST_INC:
case ZEND_PRE_DEC:
case ZEND_POST_DEC:
return is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def);
case ZEND_ASSIGN_OP:
return is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)
|| ssa->vars[ssa_op->op1_def].escape_state != ESCAPE_STATE_NO_ESCAPE;
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
if (is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)
|| ssa->vars[ssa_op->op1_def].escape_state != ESCAPE_STATE_NO_ESCAPE) {
return 1;
}
if (!reorder_dtor_effects) {
opline++;
ssa_op++;
if (opline->op1_type != IS_CONST
&& (OP1_INFO() & MAY_HAVE_DTOR)) {
/* DCE might shorten lifetime */
return 1;
}
}
return 0;
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
if (is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)
|| ssa->vars[ssa_op->op1_def].escape_state != ESCAPE_STATE_NO_ESCAPE) {
return 1;
}
return 0;
case ZEND_BIND_STATIC:
if (op_array->static_variables) {
/* Implicit and Explicit bind static is effectively prologue of closure so
report it has side effects like RECV, RECV_INIT; This allows us to
reflect on the closure and discover used variable at runtime */
if ((opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) {
return 1;
}
if ((opline->extended_value & ZEND_BIND_REF) != 0) {
zval *value =
(zval*)((char*)op_array->static_variables->arData +
(opline->extended_value & ~ZEND_BIND_REF));
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
/* AST may contain undefined constants */
return 1;
}
}
}
return 0;
case ZEND_CHECK_VAR:
return (OP1_INFO() & MAY_BE_UNDEF) != 0;
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
/* Model as not having side-effects -- let the side-effect be introduced by
* FE_FETCH if the array is not known to be non-empty. */
return (OP1_INFO() & MAY_BE_ANY) != MAY_BE_ARRAY;
default:
/* For everything we didn't handle, assume a side-effect */
return 1;
}
}
static zend_always_inline void add_to_worklists(context *ctx, int var_num, int check) {
zend_ssa_var *var = &ctx->ssa->vars[var_num];
if (var->definition >= 0) {
if (!check || zend_bitset_in(ctx->instr_dead, var->definition)) {
zend_bitset_incl(ctx->instr_worklist, var->definition);
}
} else if (var->definition_phi) {
if (!check || zend_bitset_in(ctx->phi_dead, var_num)) {
zend_bitset_incl(ctx->phi_worklist, var_num);
}
}
}
static inline void add_to_phi_worklist_no_val(context *ctx, int var_num) {
zend_ssa_var *var = &ctx->ssa->vars[var_num];
if (var->definition_phi && zend_bitset_in(ctx->phi_dead, var_num)) {
zend_bitset_incl(ctx->phi_worklist_no_val, var_num);
}
}
static zend_always_inline void add_operands_to_worklists(context *ctx, zend_op *opline, zend_ssa_op *ssa_op, zend_ssa *ssa, int check) {
if (ssa_op->result_use >= 0) {
add_to_worklists(ctx, ssa_op->result_use, check);
}
if (ssa_op->op1_use >= 0) {
if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)
|| (opline->opcode == ZEND_ASSIGN
&& (ssa->var_info[ssa_op->op1_use].type & MAY_BE_REF) != 0)) {
add_to_worklists(ctx, ssa_op->op1_use, check);
} else {
add_to_phi_worklist_no_val(ctx, ssa_op->op1_use);
}
}
if (ssa_op->op2_use >= 0) {
if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)
|| (opline->opcode == ZEND_FE_FETCH_R
&& (ssa->var_info[ssa_op->op2_use].type & MAY_BE_REF) != 0)) {
add_to_worklists(ctx, ssa_op->op2_use, check);
} else {
add_to_phi_worklist_no_val(ctx, ssa_op->op2_use);
}
}
}
static zend_always_inline void add_phi_sources_to_worklists(context *ctx, zend_ssa_phi *phi, int check) {
zend_ssa *ssa = ctx->ssa;
int source;
FOREACH_PHI_SOURCE(phi, source) {
add_to_worklists(ctx, source, check);
} FOREACH_PHI_SOURCE_END();
}
static inline bool is_var_dead(context *ctx, int var_num) {
zend_ssa_var *var = &ctx->ssa->vars[var_num];
if (var->definition_phi) {
return zend_bitset_in(ctx->phi_dead, var_num);
} else if (var->definition >= 0) {
return zend_bitset_in(ctx->instr_dead, var->definition);
} else {
/* Variable has no definition, so either the definition has already been removed (var is
* dead) or this is one of the implicit variables at the start of the function (for our
* purposes live) */
return var_num >= ctx->op_array->last_var;
}
}
// Sometimes we can mark the var as EXT_UNUSED
static bool try_remove_var_def(context *ctx, int free_var, int use_chain, zend_op *opline) {
if (use_chain >= 0) {
return 0;
}
zend_ssa_var *var = &ctx->ssa->vars[free_var];
int def = var->definition;
if (def >= 0) {
zend_ssa_op *def_op = &ctx->ssa->ops[def];
if (def_op->result_def == free_var
&& var->phi_use_chain == NULL
&& var->use_chain == (opline - ctx->op_array->opcodes)) {
zend_op *def_opline = &ctx->op_array->opcodes[def];
switch (def_opline->opcode) {
case ZEND_ASSIGN:
case ZEND_ASSIGN_REF:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_REF:
case ZEND_ASSIGN_STATIC_PROP:
case ZEND_ASSIGN_STATIC_PROP_REF:
case ZEND_ASSIGN_OP:
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:
case ZEND_ASSIGN_STATIC_PROP_OP:
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
case ZEND_PRE_INC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_DEC_OBJ:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_DO_FCALL:
case ZEND_INCLUDE_OR_EVAL:
case ZEND_YIELD:
case ZEND_YIELD_FROM:
case ZEND_ASSERT_CHECK:
def_opline->result_type = IS_UNUSED;
def_opline->result.var = 0;
def_op->result_def = -1;
var->definition = -1;
return 1;
default:
break;
}
}
}
return 0;
}
static zend_always_inline zend_bool may_be_refcounted(uint32_t type) {
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
}
static inline bool is_free_of_live_var(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
switch (opline->opcode) {
case ZEND_FREE:
/* It is always safe to remove FREEs of non-refcounted values, even if they are live. */
if (!may_be_refcounted(ctx->ssa->var_info[ssa_op->op1_use].type)) {
return 0;
}
ZEND_FALLTHROUGH;
case ZEND_FE_FREE:
return !is_var_dead(ctx, ssa_op->op1_use);
default:
return 0;
}
}
/* Returns whether the instruction has been DCEd */
static bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
zend_ssa *ssa = ctx->ssa;
int free_var = -1;
zend_uchar free_var_type;
if (opline->opcode == ZEND_NOP) {
return 0;
}
/* We mark FREEs as dead, but they're only really dead if the destroyed var is dead */
if (is_free_of_live_var(ctx, opline, ssa_op)) {
return 0;
}
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))&& !is_var_dead(ctx, ssa_op->op1_use)) {
if (!try_remove_var_def(ctx, ssa_op->op1_use, ssa_op->op1_use_chain, opline)) {
if (may_be_refcounted(ssa->var_info[ssa_op->op1_use].type)
&& opline->opcode != ZEND_CASE && opline->opcode != ZEND_CASE_STRICT) {
free_var = ssa_op->op1_use;
free_var_type = opline->op1_type;
}
}
}
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op2_use)) {
if (!try_remove_var_def(ctx, ssa_op->op2_use, ssa_op->op2_use_chain, opline)) {
if (may_be_refcounted(ssa->var_info[ssa_op->op2_use].type)) {
if (free_var >= 0) {
// TODO: We can't free two vars. Keep instruction alive.
zend_bitset_excl(ctx->instr_dead, opline - ctx->op_array->opcodes);
return 0;
}
free_var = ssa_op->op2_use;
free_var_type = opline->op2_type;
}
}
}
zend_ssa_rename_defs_of_instr(ctx->ssa, ssa_op);
zend_ssa_remove_instr(ctx->ssa, opline, ssa_op);
if (free_var >= 0) {
opline->opcode = ZEND_FREE;
opline->op1.var = EX_NUM_TO_VAR(ssa->vars[free_var].var);
opline->op1_type = free_var_type;
ssa_op->op1_use = free_var;
ssa_op->op1_use_chain = ssa->vars[free_var].use_chain;
ssa->vars[free_var].use_chain = ssa_op - ssa->ops;
return 0;
}
return 1;
}
static inline int get_common_phi_source(zend_ssa *ssa, zend_ssa_phi *phi) {
int common_source = -1;
int source;
FOREACH_PHI_SOURCE(phi, source) {
if (common_source == -1) {
common_source = source;
} else if (common_source != source && source != phi->ssa_var) {
return -1;
}
} FOREACH_PHI_SOURCE_END();
ZEND_ASSERT(common_source != -1);
return common_source;
}
static void try_remove_trivial_phi(context *ctx, zend_ssa_phi *phi) {
zend_ssa *ssa = ctx->ssa;
if (phi->pi < 0) {
/* Phi assignment with identical source operands */
int common_source = get_common_phi_source(ssa, phi);
if (common_source >= 0) {
zend_ssa_rename_var_uses(ssa, phi->ssa_var, common_source, 1);
zend_ssa_remove_phi(ssa, phi);
}
} else {
/* Pi assignment that is only used in Phi/Pi assignments */
// TODO What if we want to rerun type inference after DCE? Maybe separate this?
/*ZEND_ASSERT(phi->sources[0] != -1);
if (ssa->vars[phi->ssa_var].use_chain < 0) {
zend_ssa_rename_var_uses_keep_types(ssa, phi->ssa_var, phi->sources[0], 1);
zend_ssa_remove_phi(ssa, phi);
}*/
}
}
static inline bool may_break_varargs(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_op *ssa_op) {
if (ssa_op->op1_def >= 0
&& ssa->vars[ssa_op->op1_def].var < op_array->num_args) {
return 1;
}
if (ssa_op->op2_def >= 0
&& ssa->vars[ssa_op->op2_def].var < op_array->num_args) {
return 1;
}
if (ssa_op->result_def >= 0
&& ssa->vars[ssa_op->result_def].var < op_array->num_args) {
return 1;
}
return 0;
}
int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects) {
int i;
zend_ssa_phi *phi;
int removed_ops = 0;
/* DCE of CV operations that changes arguments may affect vararg functions. */
bool has_varargs = (ssa->cfg.flags & ZEND_FUNC_VARARG) != 0;
context ctx;
ctx.ssa = ssa;
ctx.op_array = op_array;
ctx.reorder_dtor_effects = reorder_dtor_effects;
/* We have no dedicated phi vector, so we use the whole ssa var vector instead */
ctx.instr_worklist_len = zend_bitset_len(op_array->last);
ctx.instr_worklist = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len);
memset(ctx.instr_worklist, 0, sizeof(zend_ulong) * ctx.instr_worklist_len);
ctx.phi_worklist_len = zend_bitset_len(ssa->vars_count);
ctx.phi_worklist = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len);
memset(ctx.phi_worklist, 0, sizeof(zend_ulong) * ctx.phi_worklist_len);
ctx.phi_worklist_no_val = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len);
memset(ctx.phi_worklist_no_val, 0, sizeof(zend_ulong) * ctx.phi_worklist_len);
/* Optimistically assume all instructions and phis to be dead */
ctx.instr_dead = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len);
memset(ctx.instr_dead, 0, sizeof(zend_ulong) * ctx.instr_worklist_len);
ctx.phi_dead = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len);
memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len);
/* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one
* of the producing instructions, as it combines producing the result with control flow.
* This can be made more precise if there are any cases where this is not the case. */
FOREACH_PHI(phi) {
if (phi->var >= op_array->last_var
&& may_be_refcounted(ssa->var_info[phi->ssa_var].type)) {
zend_bitset_excl(ctx.phi_dead, phi->ssa_var);
add_phi_sources_to_worklists(&ctx, phi, 0);
}
} FOREACH_PHI_END();
/* Mark reachable instruction without side effects as dead */
int b = ssa->cfg.blocks_count;
while (b > 0) {
int op_data = -1;
b--;
zend_basic_block *block = &ssa->cfg.blocks[b];
if (!(block->flags & ZEND_BB_REACHABLE)) {
continue;
}
i = block->start + block->len;
while (i > block->start) {
i--;
if (op_array->opcodes[i].opcode == ZEND_OP_DATA) {
op_data = i;
continue;
}
if (zend_bitset_in(ctx.instr_worklist, i)) {
zend_bitset_excl(ctx.instr_worklist, i);
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], ssa, 0);
if (op_data >= 0) {
add_operands_to_worklists(&ctx, &op_array->opcodes[op_data], &ssa->ops[op_data], ssa, 0);
}
} else if (may_have_side_effects(op_array, ssa, &op_array->opcodes[i], &ssa->ops[i], ctx.reorder_dtor_effects)
|| zend_may_throw(&op_array->opcodes[i], &ssa->ops[i], op_array, ssa)
|| (has_varargs && may_break_varargs(op_array, ssa, &ssa->ops[i]))) {
if (op_array->opcodes[i].opcode == ZEND_NEW
&& op_array->opcodes[i+1].opcode == ZEND_DO_FCALL
&& ssa->ops[i].result_def >= 0
&& ssa->vars[ssa->ops[i].result_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
zend_bitset_incl(ctx.instr_dead, i);
zend_bitset_incl(ctx.instr_dead, i+1);
} else {
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], ssa, 0);
if (op_data >= 0) {
add_operands_to_worklists(&ctx, &op_array->opcodes[op_data], &ssa->ops[op_data], ssa, 0);
}
}
} else {
zend_bitset_incl(ctx.instr_dead, i);
if (op_data >= 0) {
zend_bitset_incl(ctx.instr_dead, op_data);
}
}
op_data = -1;
}
}
/* Propagate liveness backwards to all definitions of used vars */
while (!zend_bitset_empty(ctx.instr_worklist, ctx.instr_worklist_len)
|| !zend_bitset_empty(ctx.phi_worklist, ctx.phi_worklist_len)) {
while ((i = zend_bitset_pop_first(ctx.instr_worklist, ctx.instr_worklist_len)) >= 0) {
zend_bitset_excl(ctx.instr_dead, i);
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], ssa, 1);
if (i < op_array->last && op_array->opcodes[i+1].opcode == ZEND_OP_DATA) {
zend_bitset_excl(ctx.instr_dead, i+1);
add_operands_to_worklists(&ctx, &op_array->opcodes[i+1], &ssa->ops[i+1], ssa, 1);
}
}
while ((i = zend_bitset_pop_first(ctx.phi_worklist, ctx.phi_worklist_len)) >= 0) {
zend_bitset_excl(ctx.phi_dead, i);
zend_bitset_excl(ctx.phi_worklist_no_val, i);
add_phi_sources_to_worklists(&ctx, ssa->vars[i].definition_phi, 1);
}
}
/* Eliminate dead instructions */
ZEND_BITSET_FOREACH(ctx.instr_dead, ctx.instr_worklist_len, i) {
removed_ops += dce_instr(&ctx, &op_array->opcodes[i], &ssa->ops[i]);
} ZEND_BITSET_FOREACH_END();
/* Improper uses don't count as "uses" for the purpose of instruction elimination,
* but we have to retain phis defining them.
* Propagate this information backwards, marking any phi with an improperly used
* target as non-dead. */
while ((i = zend_bitset_pop_first(ctx.phi_worklist_no_val, ctx.phi_worklist_len)) >= 0) {
zend_ssa_phi *phi = ssa->vars[i].definition_phi;
int source;
zend_bitset_excl(ctx.phi_dead, i);
FOREACH_PHI_SOURCE(phi, source) {
add_to_phi_worklist_no_val(&ctx, source);
} FOREACH_PHI_SOURCE_END();
}
/* Now collect the actually dead phis */
FOREACH_PHI(phi) {
if (zend_bitset_in(ctx.phi_dead, phi->ssa_var)) {
zend_ssa_remove_uses_of_var(ssa, phi->ssa_var);
zend_ssa_remove_phi(ssa, phi);
} else {
/* Remove trivial phis (phis with identical source operands) */
try_remove_trivial_phi(&ctx, phi);
}
} FOREACH_PHI_END();
return removed_ops;
}
File diff suppressed because it is too large. Load diff
-538
View File
@@ -1,538 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache, Escape Analysis |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_bitset.h"
#include "zend_cfg.h"
#include "zend_ssa.h"
#include "zend_inference.h"
#include "zend_dump.h"
/*
* T. Kotzmann and H. Mossenbock. Escape analysis in the context of dynamic
* compilation and deoptimization. In Proceedings of the International
* Conference on Virtual Execution Environments, pages 111-120, Chicago,
* June 2005
*/
static zend_always_inline void union_find_init(int *parent, int *size, int count) /* {{{ */
{
int i;
for (i = 0; i < count; i++) {
parent[i] = i;
size[i] = 1;
}
}
/* }}} */
static zend_always_inline int union_find_root(int *parent, int i) /* {{{ */
{
int p = parent[i];
while (i != p) {
p = parent[p];
parent[i] = p;
i = p;
p = parent[i];
}
return i;
}
/* }}} */
static zend_always_inline void union_find_unite(int *parent, int *size, int i, int j) /* {{{ */
{
int r1 = union_find_root(parent, i);
int r2 = union_find_root(parent, j);
if (r1 != r2) {
if (size[r1] < size[r2]) {
parent[r1] = r2;
size[r2] += size[r1];
} else {
parent[r2] = r1;
size[r1] += size[r2];
}
}
}
/* }}} */
static int zend_build_equi_escape_sets(int *parent, zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
{
zend_ssa_var *ssa_vars = ssa->vars;
int ssa_vars_count = ssa->vars_count;
zend_ssa_phi *p;
int i, j;
int *size;
ALLOCA_FLAG(use_heap)
size = do_alloca(sizeof(int) * ssa_vars_count, use_heap);
if (!size) {
return FAILURE;
}
union_find_init(parent, size, ssa_vars_count);
for (i = 0; i < ssa_vars_count; i++) {
if (ssa_vars[i].definition_phi) {
p = ssa_vars[i].definition_phi;
if (p->pi >= 0) {
union_find_unite(parent, size, i, p->sources[0]);
} else {
for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
union_find_unite(parent, size, i, p->sources[j]);
}
}
} else if (ssa_vars[i].definition >= 0) {
int def = ssa_vars[i].definition;
zend_ssa_op *op = ssa->ops + def;
zend_op *opline = op_array->opcodes + def;
if (op->op1_def >= 0) {
if (op->op1_use >= 0) {
if (opline->opcode != ZEND_ASSIGN) {
union_find_unite(parent, size, op->op1_def, op->op1_use);
}
}
if (opline->opcode == ZEND_ASSIGN && op->op2_use >= 0) {
union_find_unite(parent, size, op->op1_def, op->op2_use);
}
}
if (op->op2_def >= 0) {
if (op->op2_use >= 0) {
union_find_unite(parent, size, op->op2_def, op->op2_use);
}
}
if (op->result_def >= 0) {
if (op->result_use >= 0) {
if (opline->opcode != ZEND_QM_ASSIGN) {
union_find_unite(parent, size, op->result_def, op->result_use);
}
}
if (opline->opcode == ZEND_QM_ASSIGN && op->op1_use >= 0) {
union_find_unite(parent, size, op->result_def, op->op1_use);
}
if (opline->opcode == ZEND_ASSIGN && op->op2_use >= 0) {
union_find_unite(parent, size, op->result_def, op->op2_use);
}
if (opline->opcode == ZEND_ASSIGN && op->op1_def >= 0) {
union_find_unite(parent, size, op->result_def, op->op1_def);
}
}
}
}
for (i = 0; i < ssa_vars_count; i++) {
parent[i] = union_find_root(parent, i);
}
free_alloca(size, use_heap);
return SUCCESS;
}
/* }}} */
static inline zend_class_entry *get_class_entry(const zend_script *script, zend_string *lcname) /* {{{ */
{
zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
if (ce) {
return ce;
}
ce = zend_hash_find_ptr(CG(class_table), lcname);
if (ce && ce->type == ZEND_INTERNAL_CLASS) {
return ce;
}
return NULL;
}
/* }}} */
static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var, const zend_script *script) /* {{{ */
{
zend_ssa_op *ssa_op = ssa->ops + def;
zend_op *opline = op_array->opcodes + def;
if (ssa_op->result_def == var) {
switch (opline->opcode) {
case ZEND_INIT_ARRAY:
return 1;
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
uint32_t forbidden_flags =
/* These flags will always cause an exception */
ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
| ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT;
if (ce && !ce->parent && !ce->create_object && !ce->constructor &&
!ce->destructor && !ce->__get && !ce->__set &&
!(ce->ce_flags & forbidden_flags) &&
(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
return 1;
}
}
break;
case ZEND_QM_ASSIGN:
if (opline->op1_type == IS_CONST
&& Z_TYPE_P(CRT_CONSTANT(opline->op1)) == IS_ARRAY) {
return 1;
}
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
return 1;
}
break;
case ZEND_ASSIGN:
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
return 1;
}
break;
}
} else if (ssa_op->op1_def == var) {
switch (opline->opcode) {
case ZEND_ASSIGN:
if (opline->op2_type == IS_CONST
&& Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_ARRAY) {
return 1;
}
if (opline->op2_type == IS_CV && (OP2_INFO() & MAY_BE_ARRAY)) {
return 1;
}
break;
case ZEND_ASSIGN_DIM:
if (OP1_INFO() & (MAY_BE_UNDEF | MAY_BE_NULL | MAY_BE_FALSE)) {
/* implicit object/array allocation */
return 1;
}
break;
}
}
return 0;
}
/* }}} */
static int is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var, const zend_script *script) /* {{{ */
{
zend_ssa_op *op = ssa->ops + def;
zend_op *opline = op_array->opcodes + def;
if (op->result_def == var) {
switch (opline->opcode) {
case ZEND_INIT_ARRAY:
case ZEND_ADD_ARRAY_ELEMENT:
case ZEND_QM_ASSIGN:
case ZEND_ASSIGN:
return 1;
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
if (ce && !ce->create_object && !ce->constructor &&
!ce->destructor && !ce->__get && !ce->__set && !ce->parent) {
return 1;
}
}
break;
}
} else if (op->op1_def == var) {
switch (opline->opcode) {
case ZEND_ASSIGN:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_REF:
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
return 1;
}
}
return 0;
}
/* }}} */
static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int var) /* {{{ */
{
zend_ssa_op *ssa_op = ssa->ops + use;
zend_op *opline = op_array->opcodes + use;
if (ssa_op->op1_use == var) {
switch (opline->opcode) {
case ZEND_ASSIGN:
/* no_val */
break;
case ZEND_QM_ASSIGN:
if (opline->op1_type == IS_CV) {
if (OP1_INFO() & MAY_BE_OBJECT) {
/* object aliasing */
return 1;
}
}
break;
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
case ZEND_FETCH_DIM_R:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_DIM_IS:
case ZEND_FETCH_OBJ_IS:
break;
case ZEND_ASSIGN_OP:
return 1;
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:
case ZEND_ASSIGN_STATIC_PROP_OP:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_REF:
break;
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
break;
case ZEND_INIT_ARRAY:
case ZEND_ADD_ARRAY_ELEMENT:
if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
return 1;
}
if (OP1_INFO() & MAY_BE_OBJECT) {
/* object aliasing */
return 1;
}
/* reference dependencies processed separately */
break;
case ZEND_OP_DATA:
if ((opline-1)->opcode != ZEND_ASSIGN_DIM
&& (opline-1)->opcode != ZEND_ASSIGN_OBJ) {
return 1;
}
if (OP1_INFO() & MAY_BE_OBJECT) {
/* object aliasing */
return 1;
}
opline--;
ssa_op--;
if (opline->op1_type != IS_CV
|| (OP1_INFO() & MAY_BE_REF)
|| (ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias)) {
/* assignment into escaping structure */
return 1;
}
/* reference dependencies processed separately */
break;
default:
return 1;
}
}
if (ssa_op->op2_use == var) {
switch (opline->opcode) {
case ZEND_ASSIGN:
if (opline->op1_type != IS_CV
|| (OP1_INFO() & MAY_BE_REF)
|| (ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias)) {
/* assignment into escaping variable */
return 1;
}
if (opline->op2_type == IS_CV || opline->result_type != IS_UNUSED) {
if (OP2_INFO() & MAY_BE_OBJECT) {
/* object aliasing */
return 1;
}
}
break;
default:
return 1;
}
}
if (ssa_op->result_use == var) {
switch (opline->opcode) {
case ZEND_ASSIGN:
case ZEND_QM_ASSIGN:
case ZEND_INIT_ARRAY:
case ZEND_ADD_ARRAY_ELEMENT:
break;
default:
return 1;
}
}
return 0;
}
/* }}} */
int zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
{
zend_ssa_var *ssa_vars = ssa->vars;
int ssa_vars_count = ssa->vars_count;
int i, root, use;
int *ees;
bool has_allocations;
int num_non_escaped;
ALLOCA_FLAG(use_heap)
if (!ssa_vars) {
return SUCCESS;
}
has_allocations = 0;
for (i = op_array->last_var; i < ssa_vars_count; i++) {
if (ssa_vars[i].definition >= 0
&& (ssa->var_info[i].type & (MAY_BE_ARRAY|MAY_BE_OBJECT))
&& is_allocation_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
has_allocations = 1;
break;
}
}
if (!has_allocations) {
return SUCCESS;
}
/* 1. Build EES (Equi-Escape Sets) */
ees = do_alloca(sizeof(int) * ssa_vars_count, use_heap);
if (!ees) {
return FAILURE;
}
if (zend_build_equi_escape_sets(ees, op_array, ssa) != SUCCESS) {
return FAILURE;
}
/* 2. Identify Allocations */
num_non_escaped = 0;
for (i = op_array->last_var; i < ssa_vars_count; i++) {
root = ees[i];
if (ssa_vars[root].escape_state > ESCAPE_STATE_NO_ESCAPE) {
/* already escape. skip */
} else if (ssa_vars[i].alias && (ssa->var_info[i].type & MAY_BE_REF)) {
if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
num_non_escaped--;
}
ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
} else if (ssa_vars[i].definition >= 0
&& (ssa->var_info[i].type & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
if (!is_local_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
num_non_escaped--;
}
ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
} else if (ssa_vars[root].escape_state == ESCAPE_STATE_UNKNOWN
&& is_allocation_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
ssa_vars[root].escape_state = ESCAPE_STATE_NO_ESCAPE;
num_non_escaped++;
}
}
}
/* 3. Mark escaped EES */
if (num_non_escaped) {
for (i = 0; i < ssa_vars_count; i++) {
if (ssa_vars[i].use_chain >= 0) {
root = ees[i];
if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
FOREACH_USE(ssa_vars + i, use) {
if (is_escape_use(op_array, ssa, use, i)) {
ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
num_non_escaped--;
if (num_non_escaped == 0) {
i = ssa_vars_count;
}
break;
}
} FOREACH_USE_END();
}
}
}
}
/* 4. Process referential dependencies */
if (num_non_escaped) {
bool changed;
do {
changed = 0;
for (i = 0; i < ssa_vars_count; i++) {
if (ssa_vars[i].use_chain >= 0) {
root = ees[i];
if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
FOREACH_USE(ssa_vars + i, use) {
zend_ssa_op *op = ssa->ops + use;
zend_op *opline = op_array->opcodes + use;
int enclosing_root;
if (opline->opcode == ZEND_OP_DATA &&
((opline-1)->opcode == ZEND_ASSIGN_DIM ||
(opline-1)->opcode == ZEND_ASSIGN_OBJ ||
(opline-1)->opcode == ZEND_ASSIGN_OBJ_REF) &&
op->op1_use == i &&
(op-1)->op1_use >= 0) {
enclosing_root = ees[(op-1)->op1_use];
} else if ((opline->opcode == ZEND_INIT_ARRAY ||
opline->opcode == ZEND_ADD_ARRAY_ELEMENT) &&
op->op1_use == i &&
op->result_def >= 0) {
enclosing_root = ees[op->result_def];
} else {
continue;
}
if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN ||
ssa_vars[enclosing_root].escape_state > ssa_vars[root].escape_state) {
if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN) {
ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
} else {
ssa_vars[root].escape_state = ssa_vars[enclosing_root].escape_state;
}
if (ssa_vars[root].escape_state == ESCAPE_STATE_GLOBAL_ESCAPE) {
num_non_escaped--;
if (num_non_escaped == 0) {
changed = 0;
} else {
changed = 1;
}
break;
} else {
changed = 1;
}
}
} FOREACH_USE_END();
}
}
}
} while (changed);
}
/* 5. Propagate values of escape sets to variables */
for (i = 0; i < ssa_vars_count; i++) {
root = ees[i];
if (i != root) {
ssa_vars[i].escape_state = ssa_vars[root].escape_state;
}
}
free_alloca(ees, use_heap);
return SUCCESS;
}
/* }}} */
-105
View File
@@ -1,105 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
/* pass 10:
* - remove NOPs
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *end, *opline;
uint32_t new_count, i, shift;
int j;
uint32_t *shiftlist;
ALLOCA_FLAG(use_heap);
shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap);
i = new_count = shift = 0;
end = op_array->opcodes + op_array->last;
for (opline = op_array->opcodes; opline < end; opline++) {
/* Kill JMP-over-NOP-s */
if (opline->opcode == ZEND_JMP && ZEND_OP1_JMP_ADDR(opline) > op_array->opcodes + i) {
/* check if there are only NOPs under the branch */
zend_op *target = ZEND_OP1_JMP_ADDR(opline) - 1;
while (target->opcode == ZEND_NOP) {
target--;
}
if (target == opline) {
/* only NOPs */
opline->opcode = ZEND_NOP;
}
}
shiftlist[i++] = shift;
if (opline->opcode == ZEND_NOP) {
shift++;
} else {
if (shift) {
zend_op *new_opline = op_array->opcodes + new_count;
*new_opline = *opline;
zend_optimizer_migrate_jump(op_array, new_opline, opline);
}
new_count++;
}
}
if (shift) {
op_array->last = new_count;
end = op_array->opcodes + op_array->last;
/* update JMPs */
for (opline = op_array->opcodes; opline<end; opline++) {
zend_optimizer_shift_jump(op_array, opline, shiftlist);
}
/* update try/catch array */
for (j = 0; j < op_array->last_try_catch; j++) {
op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op];
if (op_array->try_catch_array[j].finally_op) {
op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op];
op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
}
}
/* update early binding list */
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
uint32_t *opline_num = &ctx->script->first_early_binding_opline;
ZEND_ASSERT(op_array == &ctx->script->main_op_array);
do {
*opline_num -= shiftlist[*opline_num];
opline_num = &op_array->opcodes[*opline_num].result.opline_num;
} while (*opline_num != (uint32_t)-1);
}
}
free_alloca(shiftlist, use_heap);
}
-336
View File
@@ -1,336 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
| Xinchen Hui <laruence@php.net> |
+----------------------------------------------------------------------+
*/
/* pass 4
* - optimize INIT_FCALL_BY_NAME to DO_FCALL
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
#define ZEND_OP1_IS_CONST_STRING(opline) \
(opline->op1_type == IS_CONST && \
Z_TYPE(op_array->literals[(opline)->op1.constant]) == IS_STRING)
#define ZEND_OP2_IS_CONST_STRING(opline) \
(opline->op2_type == IS_CONST && \
Z_TYPE(op_array->literals[(opline)->op2.constant]) == IS_STRING)
typedef struct _optimizer_call_info {
zend_function *func;
zend_op *opline;
bool is_prototype;
bool try_inline;
uint32_t func_arg_num;
} optimizer_call_info;
static void zend_delete_call_instructions(zend_op *opline)
{
int call = 0;
while (1) {
switch (opline->opcode) {
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_FCALL:
if (call == 0) {
MAKE_NOP(opline);
return;
}
ZEND_FALLTHROUGH;
case ZEND_NEW:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL:
call--;
break;
case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
call++;
break;
case ZEND_SEND_VAL:
case ZEND_SEND_VAR:
if (call == 0) {
if (opline->op1_type == IS_CONST) {
MAKE_NOP(opline);
} else if (opline->op1_type == IS_CV) {
opline->opcode = ZEND_CHECK_VAR;
opline->extended_value = 0;
opline->result.var = 0;
} else {
opline->opcode = ZEND_FREE;
opline->extended_value = 0;
opline->result.var = 0;
}
}
break;
}
opline--;
}
}
static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func)
{
if (func->type == ZEND_USER_FUNCTION
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS))
/* TODO: function copied from trait may be inconsistent ??? */
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
&& fcall->extended_value >= func->op_array.required_num_args
&& func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) {
zend_op *ret_opline = func->op_array.opcodes + func->op_array.num_args;
if (ret_opline->op1_type == IS_CONST) {
uint32_t i, num_args = func->op_array.num_args;
num_args += (func->op_array.fn_flags & ZEND_ACC_VARIADIC) != 0;
if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL
&& !(func->op_array.fn_flags & ZEND_ACC_STATIC)) {
/* Don't inline static call to instance method. */
return;
}
for (i = 0; i < num_args; i++) {
/* Don't inline functions with by-reference arguments. This would require
* correct handling of INDIRECT arguments. */
if (ZEND_ARG_SEND_MODE(&func->op_array.arg_info[i])) {
return;
}
}
if (fcall->extended_value < func->op_array.num_args) {
/* don't inline functions with named constants in default arguments */
i = fcall->extended_value;
do {
if (Z_TYPE_P(CRT_CONSTANT_EX(&func->op_array, &func->op_array.opcodes[i], func->op_array.opcodes[i].op2)) == IS_CONSTANT_AST) {
return;
}
i++;
} while (i < func->op_array.num_args);
}
if (RETURN_VALUE_USED(opline)) {
zval zv;
ZVAL_COPY(&zv, CRT_CONSTANT_EX(&func->op_array, ret_opline, ret_opline->op1));
opline->opcode = ZEND_QM_ASSIGN;
opline->op1_type = IS_CONST;
opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
SET_UNUSED(opline->op2);
} else {
MAKE_NOP(opline);
}
zend_delete_call_instructions(opline-1);
}
}
}
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
int call = 0;
void *checkpoint;
optimizer_call_info *call_stack;
if (op_array->last < 2) {
return;
}
checkpoint = zend_arena_checkpoint(ctx->arena);
call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info));
while (opline < end) {
switch (opline->opcode) {
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_FCALL:
case ZEND_NEW:
/* The argument passing optimizations are valid for prototypes as well,
* as inheritance cannot change between ref <-> non-ref arguments. */
call_stack[call].func = zend_optimizer_get_called_func(
ctx->script, op_array, opline, &call_stack[call].is_prototype);
call_stack[call].try_inline =
!call_stack[call].is_prototype && opline->opcode != ZEND_NEW;
ZEND_FALLTHROUGH;
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL:
call_stack[call].opline = opline;
call_stack[call].func_arg_num = (uint32_t)-1;
call++;
break;
case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
call--;
if (call_stack[call].func && call_stack[call].opline) {
zend_op *fcall = call_stack[call].opline;
if (fcall->opcode == ZEND_INIT_FCALL) {
/* nothing to do */
} else if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
literal_dtor(&ZEND_OP2_LITERAL(fcall));
fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
literal_dtor(&op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
} else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL
|| fcall->opcode == ZEND_INIT_METHOD_CALL
|| fcall->opcode == ZEND_NEW) {
/* We don't have specialized opcodes for this, do nothing */
} else {
ZEND_UNREACHABLE();
}
if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level)
&& call_stack[call].try_inline) {
zend_try_inline_call(op_array, fcall, opline, call_stack[call].func);
}
}
call_stack[call].func = NULL;
call_stack[call].opline = NULL;
call_stack[call].try_inline = 0;
call_stack[call].func_arg_num = (uint32_t)-1;
break;
case ZEND_FETCH_FUNC_ARG:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_FETCH_DIM_FUNC_ARG:
if (call_stack[call - 1].func
&& call_stack[call - 1].func_arg_num != (uint32_t)-1) {
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) {
if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
opline->opcode -= 9;
} else {
opline->opcode = ZEND_FETCH_STATIC_PROP_W;
}
} else {
if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
&& opline->op2_type == IS_UNUSED) {
/* FETCH_DIM_FUNC_ARG supports UNUSED op2, while FETCH_DIM_R does not.
* Performing the replacement would create an invalid opcode. */
call_stack[call - 1].try_inline = 0;
break;
}
if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
opline->opcode -= 12;
} else {
opline->opcode = ZEND_FETCH_STATIC_PROP_R;
}
}
}
break;
case ZEND_SEND_VAL_EX:
if (call_stack[call - 1].func) {
if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0;
break;
}
if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
/* We won't convert it into_DO_FCALL to emit error at run-time */
call_stack[call - 1].opline = NULL;
} else {
opline->opcode = ZEND_SEND_VAL;
}
}
break;
case ZEND_CHECK_FUNC_ARG:
if (call_stack[call - 1].func) {
if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0;
call_stack[call - 1].func_arg_num = (uint32_t)-1;
break;
}
call_stack[call - 1].func_arg_num = opline->op2.num;
MAKE_NOP(opline);
}
break;
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
if (call_stack[call - 1].func) {
if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0;
break;
}
call_stack[call - 1].func_arg_num = (uint32_t)-1;
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->opcode = ZEND_SEND_REF;
} else {
opline->opcode = ZEND_SEND_VAR;
}
}
break;
case ZEND_SEND_VAR_NO_REF_EX:
if (call_stack[call - 1].func) {
if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0;
break;
}
if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->opcode = ZEND_SEND_VAR_NO_REF;
} else if (ARG_MAY_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->opcode = ZEND_SEND_VAL;
} else {
opline->opcode = ZEND_SEND_VAR;
}
}
break;
case ZEND_SEND_VAL:
case ZEND_SEND_VAR:
case ZEND_SEND_REF:
if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0;
break;
}
break;
case ZEND_SEND_UNPACK:
case ZEND_SEND_USER:
case ZEND_SEND_ARRAY:
call_stack[call - 1].try_inline = 0;
break;
default:
break;
}
opline++;
}
zend_arena_release(&ctx->arena, checkpoint);
}
-186
View File
@@ -1,186 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
#include "zend_bitset.h"
#define GET_AVAILABLE_T() \
for (i = 0; i < T; i++) { \
if (!zend_bitset_in(taken_T, i)) { \
break; \
} \
} \
zend_bitset_incl(taken_T, i); \
if (i > max) { \
max = i; \
}
void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
int T = op_array->T;
int offset = op_array->last_var;
uint32_t bitset_len;
zend_bitset taken_T; /* T index in use */
zend_op **start_of_T; /* opline where T is first used */
zend_bitset valid_T; /* Is the map_T valid */
int *map_T; /* Map's the T to its new index */
zend_op *opline, *end;
int currT;
int i;
int max = -1;
void *checkpoint = zend_arena_checkpoint(ctx->arena);
bitset_len = zend_bitset_len(T);
taken_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *));
valid_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int));
end = op_array->opcodes;
opline = &op_array->opcodes[op_array->last - 1];
/* Find T definition points */
while (opline >= end) {
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
start_of_T[VAR_NUM(opline->result.var) - offset] = opline;
}
opline--;
}
zend_bitset_clear(valid_T, bitset_len);
zend_bitset_clear(taken_T, bitset_len);
end = op_array->opcodes;
opline = &op_array->opcodes[op_array->last - 1];
while (opline >= end) {
if ((opline->op1_type & (IS_VAR | IS_TMP_VAR))) {
currT = VAR_NUM(opline->op1.var) - offset;
if (opline->opcode == ZEND_ROPE_END) {
int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
int var;
var = max;
while (var >= 0 && !zend_bitset_in(taken_T, var)) {
var--;
}
max = MAX(max, var + num);
var = var + 1;
map_T[currT] = var;
zend_bitset_incl(valid_T, currT);
zend_bitset_incl(taken_T, var);
opline->op1.var = NUM_VAR(var + offset);
while (num > 1) {
num--;
zend_bitset_incl(taken_T, var + num);
}
} else {
if (!zend_bitset_in(valid_T, currT)) {
int use_new_var = 0;
/* Code in "finally" blocks may modify temporary variables.
* We allocate new temporaries for values that need to
* relive FAST_CALLs.
*/
if ((op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) &&
(opline->opcode == ZEND_RETURN ||
opline->opcode == ZEND_GENERATOR_RETURN ||
opline->opcode == ZEND_RETURN_BY_REF ||
opline->opcode == ZEND_FREE ||
opline->opcode == ZEND_FE_FREE)) {
zend_op *curr = opline;
while (--curr >= end) {
if (curr->opcode == ZEND_FAST_CALL) {
use_new_var = 1;
break;
} else if (curr->opcode != ZEND_FREE &&
curr->opcode != ZEND_FE_FREE &&
curr->opcode != ZEND_VERIFY_RETURN_TYPE &&
curr->opcode != ZEND_DISCARD_EXCEPTION) {
break;
}
}
}
if (use_new_var) {
i = ++max;
zend_bitset_incl(taken_T, i);
} else {
GET_AVAILABLE_T();
}
map_T[currT] = i;
zend_bitset_incl(valid_T, currT);
}
opline->op1.var = NUM_VAR(map_T[currT] + offset);
}
}
if ((opline->op2_type & (IS_VAR | IS_TMP_VAR))) {
currT = VAR_NUM(opline->op2.var) - offset;
if (!zend_bitset_in(valid_T, currT)) {
GET_AVAILABLE_T();
map_T[currT] = i;
zend_bitset_incl(valid_T, currT);
}
opline->op2.var = NUM_VAR(map_T[currT] + offset);
}
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
currT = VAR_NUM(opline->result.var) - offset;
if (zend_bitset_in(valid_T, currT)) {
if (start_of_T[currT] == opline) {
/* ZEND_FAST_CALL can not share temporary var with others
* since the fast_var could also be set by ZEND_HANDLE_EXCEPTION
* which could be ahead of it */
if (opline->opcode != ZEND_FAST_CALL) {
zend_bitset_excl(taken_T, map_T[currT]);
}
}
opline->result.var = NUM_VAR(map_T[currT] + offset);
if (opline->opcode == ZEND_ROPE_INIT) {
if (start_of_T[currT] == opline) {
uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
while (num > 1) {
num--;
zend_bitset_excl(taken_T, map_T[currT]+num);
}
}
}
} else {
/* Code which gets here is using a wrongly built opcode such as RECV() */
GET_AVAILABLE_T();
map_T[currT] = i;
zend_bitset_incl(valid_T, currT);
opline->result.var = NUM_VAR(i + offset);
}
}
opline--;
}
zend_arena_release(&ctx->arena, checkpoint);
op_array->T = max + 1;
}
-685
View File
@@ -1,685 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
/* pass 1 (Simple local optimizations)
* - persistent constant substitution (true, false, null, etc)
* - constant casting (ADD expects numbers, CONCAT strings, etc)
* - constant expression evaluation
* - optimize constant conditional JMPs
* - pre-evaluate constant function calls
* - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
*/
#include "php.h"
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
(op_array == &ctx->script->main_op_array) : 0;
while (opline < end) {
switch (opline->opcode) {
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
if (opline->op1_type == IS_CONST) {
if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
convert_to_string(&ZEND_OP1_LITERAL(opline));
}
}
if (opline->op2_type == IS_CONST) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
convert_to_string(&ZEND_OP2_LITERAL(opline));
}
if (opline->op1_type == IS_CONST) {
goto constant_binary_op;
}
}
break;
case ZEND_ADD:
case ZEND_SUB:
case ZEND_MUL:
case ZEND_DIV:
case ZEND_POW:
case ZEND_MOD:
case ZEND_SL:
case ZEND_SR:
case ZEND_BW_OR:
case ZEND_BW_AND:
case ZEND_BW_XOR:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_BOOL_XOR:
case ZEND_SPACESHIP:
case ZEND_CASE:
case ZEND_CASE_STRICT:
if (opline->op1_type == IS_CONST &&
opline->op2_type == IS_CONST) {
/* binary operation with constant operands */
zval result;
constant_binary_op:
if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
literal_dtor(&ZEND_OP2_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &result);
}
}
}
break;
case ZEND_ASSIGN_OP:
if (opline->op2_type == IS_CONST) {
if (opline->extended_value == ZEND_ADD
|| opline->extended_value == ZEND_SUB
|| opline->extended_value == ZEND_MUL
|| opline->extended_value == ZEND_DIV
|| opline->extended_value == ZEND_POW) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
/* don't optimize if it should produce a runtime numeric string error */
if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
}
}
} else if (opline->extended_value == ZEND_MOD
|| opline->extended_value == ZEND_SL
|| opline->extended_value == ZEND_SR) {
zval *op2 = &ZEND_OP2_LITERAL(opline);
if (Z_TYPE_P(op2) != IS_LONG) {
if (!zend_is_op_long_compatible(op2)) {
break;
}
convert_to_long(op2);
}
} else if (opline->extended_value == ZEND_CONCAT) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
convert_to_string(&ZEND_OP2_LITERAL(opline));
}
}
}
break;
case ZEND_CAST:
if (opline->op1_type == IS_CONST) {
/* cast of constant operand */
zval result;
if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
zend_optimizer_update_op1_const(op_array, opline, &result);
}
break;
}
}
break;
case ZEND_BW_NOT:
case ZEND_BOOL_NOT:
if (opline->op1_type == IS_CONST) {
/* unary operation on constant operand */
zval result;
if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
zend_optimizer_update_op1_const(op_array, opline, &result);
}
}
}
break;
case ZEND_FETCH_CONSTANT:
if (opline->op2_type == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
/* substitute __COMPILER_HALT_OFFSET__ constant */
zend_execute_data *orig_execute_data = EG(current_execute_data);
zend_execute_data fake_execute_data;
zval *offset;
memset(&fake_execute_data, 0, sizeof(zend_execute_data));
fake_execute_data.func = (zend_function*)op_array;
EG(current_execute_data) = &fake_execute_data;
if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, offset);
}
}
EG(current_execute_data) = orig_execute_data;
break;
}
if (opline->op2_type == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
/* substitute persistent constants */
zval c;
if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
break;
}
}
if (Z_TYPE(c) == IS_CONSTANT_AST) {
break;
}
literal_dtor(&ZEND_OP2_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &c);
}
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op2_type == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
zend_class_entry *ce = NULL;
if (opline->op1_type == IS_CONST &&
Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
/* for A::B */
if (op_array->scope &&
zend_string_equals_ci(Z_STR(ZEND_OP1_LITERAL(opline)), op_array->scope->name)) {
ce = op_array->scope;
} else {
if ((ce = zend_hash_find_ptr(EG(class_table),
Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
(ce->type == ZEND_INTERNAL_CLASS &&
ce->info.internal.module->type != MODULE_PERSISTENT) ||
(ce->type == ZEND_USER_CLASS &&
ce->info.user.filename != op_array->filename)) {
break;
}
}
} else if (op_array->scope &&
opline->op1_type == IS_UNUSED &&
(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
/* for self::B */
ce = op_array->scope;
} else if (op_array->scope &&
opline->op1_type == IS_VAR &&
(opline - 1)->opcode == ZEND_FETCH_CLASS &&
((opline - 1)->op2_type == IS_UNUSED &&
((opline - 1)->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
(opline - 1)->result.var == opline->op1.var) {
/* for self::B */
ce = op_array->scope;
}
if (ce) {
zend_class_constant *cc;
zval *c, t;
if ((cc = zend_hash_find_ptr(&ce->constants_table,
Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
(ZEND_CLASS_CONST_FLAGS(cc) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
c = &cc->value;
if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
zend_ast *ast = Z_ASTVAL_P(c);
if (ast->kind != ZEND_AST_CONSTANT
|| !zend_optimizer_get_persistent_constant(zend_ast_get_constant_name(ast), &t, 1)
|| Z_TYPE(t) == IS_CONSTANT_AST) {
break;
}
} else {
ZVAL_COPY_OR_DUP(&t, c);
}
if (opline->op1_type == IS_CONST) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
} else if (opline->op1_type == IS_VAR) {
MAKE_NOP((opline - 1));
}
literal_dtor(&ZEND_OP2_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
}
}
break;
case ZEND_DO_ICALL: {
zend_op *send1_opline = opline - 1;
zend_op *send2_opline = NULL;
zend_op *init_opline = NULL;
while (send1_opline->opcode == ZEND_NOP) {
send1_opline--;
}
if (send1_opline->opcode != ZEND_SEND_VAL ||
send1_opline->op1_type != IS_CONST) {
/* don't collect constants after unknown function call */
collect_constants = 0;
break;
}
if (send1_opline->op2.num == 2) {
send2_opline = send1_opline;
send1_opline--;
while (send1_opline->opcode == ZEND_NOP) {
send1_opline--;
}
if (send1_opline->opcode != ZEND_SEND_VAL ||
send1_opline->op1_type != IS_CONST) {
/* don't collect constants after unknown function call */
collect_constants = 0;
break;
}
}
init_opline = send1_opline - 1;
while (init_opline->opcode == ZEND_NOP) {
init_opline--;
}
if (init_opline->opcode != ZEND_INIT_FCALL ||
init_opline->op2_type != IS_CONST ||
Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
/* don't collect constants after unknown function call */
collect_constants = 0;
break;
}
/* define("name", scalar); */
if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
send2_opline &&
Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
if (collect_constants) {
zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
}
if (RESULT_UNUSED(opline) &&
!zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
opline->opcode = ZEND_DECLARE_CONST;
opline->op1_type = IS_CONST;
opline->op2_type = IS_CONST;
opline->result_type = IS_UNUSED;
opline->op1.constant = send1_opline->op1.constant;
opline->op2.constant = send2_opline->op1.constant;
opline->result.num = 0;
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
MAKE_NOP(send1_opline);
MAKE_NOP(send2_opline);
}
break;
}
}
/* pre-evaluate constant functions:
constant(x)
function_exists(x)
is_callable(x)
extension_loaded(x)
*/
if (!send2_opline &&
Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"function_exists", sizeof("function_exists")-1)) ||
(Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"is_callable", sizeof("is_callable")))) {
zend_internal_function *func;
zend_string *lc_name = zend_string_tolower(
Z_STR(ZEND_OP1_LITERAL(send1_opline)));
if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
&& func->type == ZEND_INTERNAL_FUNCTION
&& func->module->type == MODULE_PERSISTENT
#ifdef ZEND_WIN32
&& func->module->handle == NULL
#endif
) {
zval t;
ZVAL_TRUE(&t);
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
zend_string_release_ex(lc_name, 0);
break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"extension_loaded", sizeof("extension_loaded")-1)) {
zval t;
zend_string *lc_name = zend_string_tolower(
Z_STR(ZEND_OP1_LITERAL(send1_opline)));
zend_module_entry *m = zend_hash_find_ptr(&module_registry,
lc_name);
zend_string_release_ex(lc_name, 0);
if (!m) {
if (PG(enable_dl)) {
break;
} else {
ZVAL_FALSE(&t);
}
} else {
if (m->type == MODULE_PERSISTENT
#ifdef ZEND_WIN32
&& m->handle == NULL
#endif
) {
ZVAL_TRUE(&t);
} else {
break;
}
}
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &t);
}
break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"constant", sizeof("constant")-1)) {
zval t;
if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
break;
/* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"dirname", sizeof("dirname") - 1) &&
IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
zval t;
ZVAL_STR(&t, dirname);
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
opline->extended_value = 0;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &t);
}
} else {
zend_string_release_ex(dirname, 0);
}
break;
}
}
/* don't collect constants after any other function call */
collect_constants = 0;
break;
}
case ZEND_STRLEN:
if (opline->op1_type == IS_CONST) {
zval t;
if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
}
break;
case ZEND_DEFINED:
{
zval c;
if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
break;
}
ZVAL_TRUE(&c);
literal_dtor(&ZEND_OP1_LITERAL(opline));
if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
MAKE_NOP(opline);
} else {
opline->opcode = ZEND_QM_ASSIGN;
zend_optimizer_update_op1_const(op_array, opline, &c);
}
}
break;
case ZEND_DECLARE_CONST:
if (collect_constants &&
Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
}
break;
#if 0
/* see ext/opcache/tests/bug78961.phpt */
// case ZEND_FETCH_R:
case ZEND_FETCH_W:
// case ZEND_FETCH_RW:
case ZEND_FETCH_IS:
// case ZEND_FETCH_FUNC_ARG:
case ZEND_FETCH_UNSET:
/* convert FETCH $GLOBALS (global), FETCH_DIM $x into FETCH $x (global) */
if ((opline->extended_value & ZEND_FETCH_GLOBAL) != 0 &&
opline->op1_type == IS_CONST &&
Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
zend_string_equals_literal(Z_STR(ZEND_OP1_LITERAL(opline)), "GLOBALS") &&
((opline + 1)->opcode == opline->opcode + 1 ||
((opline + 1)->opcode == ZEND_UNSET_DIM &&
opline->opcode == ZEND_FETCH_UNSET) ||
((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ &&
opline->opcode == ZEND_FETCH_IS)) &&
(opline + 1)->op1_type == opline->result_type &&
(opline + 1)->op1.var == opline->result.var &&
((opline + 1)->op2_type != IS_CONST ||
Z_TYPE(ZEND_OP2_LITERAL(opline + 1)) < IS_ARRAY)) {
if ((opline + 1)->opcode == ZEND_UNSET_DIM) {
(opline + 1)->opcode = ZEND_UNSET_VAR;
(opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
} else if ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) {
(opline + 1)->opcode = ZEND_ISSET_ISEMPTY_VAR;
(opline + 1)->extended_value |= ZEND_FETCH_GLOBAL;
} else {
(opline + 1)->opcode = opline->opcode;
(opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
}
(opline + 1)->op1_type = (opline + 1)->op2_type;
(opline + 1)->op1 = (opline + 1)->op2;
if ((opline + 1)->op1_type == IS_CONST &&
Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) != IS_STRING) {
convert_to_string(&ZEND_OP1_LITERAL(opline + 1));
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline + 1)));
}
SET_UNUSED((opline + 1)->op2);
MAKE_NOP(opline);
}
break;
#endif
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
/* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
in case we know it wouldn't jump */
if (opline->op1_type == IS_CONST) {
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
if (opline->opcode == ZEND_JMPZ_EX) {
opline->opcode = ZEND_QM_ASSIGN;
zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
ZVAL_TRUE(&ZEND_OP1_LITERAL(opline));
opline->op2.num = 0;
break;
}
} else {
if (opline->opcode == ZEND_JMPNZ_EX) {
opline->opcode = ZEND_QM_ASSIGN;
zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
ZVAL_FALSE(&ZEND_OP1_LITERAL(opline));
opline->op2.num = 0;
break;
}
}
}
collect_constants = 0;
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
if (opline->op1_type == IS_CONST) {
int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
if (opline->opcode == ZEND_JMPZ) {
should_jmp = !should_jmp;
}
literal_dtor(&ZEND_OP1_LITERAL(opline));
opline->op1_type = IS_UNUSED;
if (should_jmp) {
opline->opcode = ZEND_JMP;
COPY_NODE(opline->op1, opline->op2);
opline->op2.num = 0;
} else {
MAKE_NOP(opline);
break;
}
}
collect_constants = 0;
break;
case ZEND_JMPZNZ:
if (opline->op1_type == IS_CONST) {
zend_op *target_opline;
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
} else {
target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
}
literal_dtor(&ZEND_OP1_LITERAL(opline));
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
opline->op1_type = IS_UNUSED;
opline->opcode = ZEND_JMP;
}
collect_constants = 0;
break;
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_THROW:
case ZEND_MATCH_ERROR:
case ZEND_CATCH:
case ZEND_FAST_CALL:
case ZEND_FAST_RET:
case ZEND_JMP:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
case ZEND_JMP_NULL:
case ZEND_VERIFY_NEVER_TYPE:
collect_constants = 0;
break;
}
opline++;
}
}
-355
View File
@@ -1,355 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
/* pass 3: (Jump optimization)
* - optimize series of JMPs
*/
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
static zend_always_inline int in_hitlist(zend_op *target, zend_op **jmp_hitlist, int jmp_hitlist_count)
{
int i;
for (i = 0; i < jmp_hitlist_count; i++) {
if (jmp_hitlist[i] == target) {
return 1;
}
}
return 0;
}
#define CHECK_LOOP(target) \
if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
jmp_hitlist[jmp_hitlist_count++] = target; \
} else { \
break; \
}
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline;
zend_op *end;
zend_op *target;
zend_op **jmp_hitlist;
int jmp_hitlist_count;
ALLOCA_FLAG(use_heap);
jmp_hitlist = (zend_op**)do_alloca(sizeof(zend_op*)*op_array->last, use_heap);
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
switch (opline->opcode) {
case ZEND_JMP:
jmp_hitlist_count = 0;
target = ZEND_OP1_JMP_ADDR(opline);
while (1) {
if (target->opcode == ZEND_JMP) {
/* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
}
if (target == opline + 1) {
/* convert L: JMP L+1 to NOP */
MAKE_NOP(opline);
} else if (target->opcode == ZEND_JMPZNZ) {
/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
*opline = *target;
if (opline->op1_type == IS_CONST) {
zval zv;
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
goto optimize_jmpznz;
} else if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
/* JMP L, L: RETURN to immediate RETURN */
*opline = *target;
if (opline->op1_type == IS_CONST) {
zval zv;
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
} else if (opline > op_array->opcodes &&
((opline-1)->opcode == ZEND_JMPZ ||
(opline-1)->opcode == ZEND_JMPNZ)) {
if (ZEND_OP2_JMP_ADDR(opline-1) == target) {
/* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
if ((opline-1)->op1_type == IS_CV) {
(opline-1)->opcode = ZEND_CHECK_VAR;
(opline-1)->op2.num = 0;
} else if ((opline-1)->op1_type & (IS_TMP_VAR|IS_VAR)) {
(opline-1)->opcode = ZEND_FREE;
(opline-1)->op2.num = 0;
} else {
MAKE_NOP(opline-1);
}
} else {
/* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
if ((opline-1)->opcode == ZEND_JMPZ) {
(opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), target);
} else {
(opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), ZEND_OP2_JMP_ADDR(opline-1));
ZEND_SET_OP_JMP_ADDR((opline-1), (opline-1)->op2, target);
}
(opline-1)->opcode = ZEND_JMPZNZ;
}
}
break;
case ZEND_JMP_SET:
case ZEND_COALESCE:
jmp_hitlist_count = 0;
target = ZEND_OP2_JMP_ADDR(opline);
while (1) {
if (target->opcode == ZEND_JMP) {
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
jmp_hitlist_count = 0;
target = ZEND_OP2_JMP_ADDR(opline);
while (1) {
if (target->opcode == ZEND_JMP) {
/* plain JMP */
/* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == opline->opcode &&
SAME_VAR(opline->op1, target->op1)) {
/* same opcode and same var as this opcode */
/* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */
target = ZEND_OP2_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == INV_COND(opline->opcode) &&
SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to
JMPZ(X,L1+1) */
target = target + 1;
} else if (target->opcode == ZEND_JMPZNZ &&
SAME_VAR(opline->op1, target->op1)) {
target = (opline->opcode == ZEND_JMPZ) ?
ZEND_OP2_JMP_ADDR(target) :
ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
/* convert L: JMPZ L+1 to NOP */
if (target == opline + 1) {
if (opline->op1_type == IS_CV) {
opline->opcode = ZEND_CHECK_VAR;
opline->op2.num = 0;
} else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
opline->opcode = ZEND_FREE;
opline->op2.num = 0;
} else {
MAKE_NOP(opline);
}
}
break;
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
jmp_hitlist_count = 0;
target = ZEND_OP2_JMP_ADDR(opline);
while (1) {
if (target->opcode == ZEND_JMP) {
/* plain JMP */
/* JMPZ_EX(X,L1), L1: JMP(L2) => JMPZ_EX(X,L2), L1: JMP(L2) */
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == opline->opcode-3 &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* convert T=JMPZ_EX(X,L1), L1: JMPZ(T,L2) to
JMPZ_EX(X,L2) */
target = ZEND_OP2_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == opline->opcode &&
target->result.var == opline->result.var &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* convert T=JMPZ_EX(X,L1), L1: T=JMPZ_EX(T,L2) to
JMPZ_EX(X,L2) */
target = ZEND_OP2_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_JMPZNZ &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* Check for JMPZNZ with same cond variable */
target = (opline->opcode == ZEND_JMPZ_EX) ?
ZEND_OP2_JMP_ADDR(target) :
ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
CHECK_LOOP(target);
} else if (target->opcode == INV_EX_COND(opline->opcode) &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* convert T=JMPZ_EX(X,L1), L1: JMPNZ(T,L2) to
JMPZ_EX(X,L1+1) */
target = target + 1;
} else if (target->opcode == INV_EX_COND_EX(opline->opcode) &&
target->result.var == opline->result.var &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* convert T=JMPZ_EX(X,L1), L1: T=JMPNZ_EX(T,L2) to
JMPZ_EX(X,L1+1) */
target = target + 1;
} else if (target->opcode == ZEND_BOOL &&
(SAME_VAR(target->op1, opline->result) ||
SAME_VAR(target->op1, opline->op1))) {
/* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
Z = JMPZ_EX(X,L1+1) */
/* NOTE: This optimization pattern is not safe, but works, */
/* because result of JMPZ_EX instruction */
/* is not used on the following path and */
/* should be used once on the branch path. */
/* */
/* The pattern works well only if jumps processed in */
/* direct order, otherwise it breaks JMPZ_EX */
/* sequences too early. */
opline->result.var = target->result.var;
target = target + 1;
CHECK_LOOP(target);
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
/* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
if (target == opline + 1) {
opline->opcode = ZEND_BOOL;
opline->op2.num = 0;
}
break;
case ZEND_JMPZNZ:
optimize_jmpznz:
jmp_hitlist_count = 0;
target = ZEND_OP2_JMP_ADDR(opline);
while (1) {
if (target->opcode == ZEND_JMP) {
/* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
SAME_VAR(target->op1, opline->op1)) {
/* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
target = ZEND_OP2_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_JMPNZ &&
SAME_VAR(target->op1, opline->op1)) {
/* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
target = target + 1;
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
jmp_hitlist_count = 0;
target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
while (1) {
if (target->opcode == ZEND_JMP) {
/* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
target = ZEND_OP1_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_JMPNZ &&
SAME_VAR(target->op1, opline->op1)) {
/* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
target = ZEND_OP2_JMP_ADDR(target);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_JMPZ &&
SAME_VAR(target->op1, opline->op1)) {
/* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
target = target + 1;
} else if (target->opcode == ZEND_JMPZNZ &&
SAME_VAR(target->op1, opline->op1)) {
/* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
CHECK_LOOP(target);
} else if (target->opcode == ZEND_NOP) {
target = target + 1;
} else {
break;
}
opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, target);
}
if (ZEND_OP2_JMP_ADDR(opline) == target &&
!(opline->op1_type & (IS_VAR|IS_TMP_VAR))) {
/* JMPZNZ(?,L,L) -> JMP(L) */
opline->opcode = ZEND_JMP;
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
opline->extended_value = 0;
}
/* Don't convert JMPZNZ back to JMPZ/JMPNZ, because the
following JMP is not removed yet. */
break;
}
opline++;
}
free_alloca(jmp_hitlist, use_heap);
}
File diff suppressed because it is too large. Load diff
-229
View File
@@ -1,229 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Sparse Conditional Data Flow Propagation Framework |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Nikita Popov <nikic@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer_internal.h"
#include "Optimizer/scdf.h"
/* This defines a generic framework for sparse conditional dataflow propagation. The algorithm is
* based on "Sparse conditional constant propagation" by Wegman and Zadeck. We're using a
* generalized implementation as described in chapter 8.3 of the SSA book.
*
* Every SSA variable is associated with an element on a finite-height lattice, those value can only
* ever be lowered during the operation of the algorithm. If a value is lowered all instructions and
* phis using that value need to be reconsidered (this is done by adding the variable to a
* worklist). For phi functions the result is computed by applying the meet operation to the
* operands. This continues until a fixed point is reached.
*
* The algorithm is control-flow sensitive: All blocks except the start block are initially assumed
* to be unreachable. When considering a branch instruction, we determine the feasible successors
* based on the current state of the variable lattice. If a new edge becomes feasible we either have
* to mark the successor block executable and consider all instructions in it, or, if the target is
* already executable, we only have to reconsider the phi functions (as we only consider phi
* operands which are associated with a feasible edge).
*
* The generic framework requires the definition of three functions:
* * visit_instr() should recompute the lattice values of all SSA variables defined by an
* instruction.
* * visit_phi() should recompute the lattice value of the SSA variable defined by the phi. While
* doing this it should only consider operands for which scfg_is_edge_feasible() returns true.
* * get_feasible_successors() should determine the feasible successors for a branch instruction.
* Note that this callback only needs to handle conditional branches (with two successors).
*/
#if 0
#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
void scdf_mark_edge_feasible(scdf_ctx *scdf, int from, int to) {
uint32_t edge = scdf_edge(&scdf->ssa->cfg, from, to);
if (zend_bitset_in(scdf->feasible_edges, edge)) {
/* We already handled this edge */
return;
}
DEBUG_PRINT("Marking edge %d->%d feasible\n", from, to);
zend_bitset_incl(scdf->feasible_edges, edge);
if (!zend_bitset_in(scdf->executable_blocks, to)) {
if (!zend_bitset_in(scdf->block_worklist, to)) {
DEBUG_PRINT("Adding block %d to worklist\n", to);
}
zend_bitset_incl(scdf->block_worklist, to);
} else {
/* Block is already executable, only a new edge became feasible.
* Reevaluate phi nodes to account for changed source operands. */
zend_ssa_block *ssa_block = &scdf->ssa->blocks[to];
zend_ssa_phi *phi;
for (phi = ssa_block->phis; phi; phi = phi->next) {
zend_bitset_excl(scdf->phi_var_worklist, phi->ssa_var);
scdf->handlers.visit_phi(scdf, phi);
}
}
}
void scdf_init(zend_optimizer_ctx *ctx, scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa) {
scdf->op_array = op_array;
scdf->ssa = ssa;
scdf->instr_worklist_len = zend_bitset_len(op_array->last);
scdf->phi_var_worklist_len = zend_bitset_len(ssa->vars_count);
scdf->block_worklist_len = zend_bitset_len(ssa->cfg.blocks_count);
scdf->instr_worklist = zend_arena_calloc(&ctx->arena,
scdf->instr_worklist_len + scdf->phi_var_worklist_len + 2 * scdf->block_worklist_len + zend_bitset_len(ssa->cfg.edges_count),
sizeof(zend_ulong));
scdf->phi_var_worklist = scdf->instr_worklist + scdf->instr_worklist_len;
scdf->block_worklist = scdf->phi_var_worklist + scdf->phi_var_worklist_len;
scdf->executable_blocks = scdf->block_worklist + scdf->block_worklist_len;
scdf->feasible_edges = scdf->executable_blocks + scdf->block_worklist_len;
zend_bitset_incl(scdf->block_worklist, 0);
zend_bitset_incl(scdf->executable_blocks, 0);
}
void scdf_solve(scdf_ctx *scdf, const char *name) {
zend_ssa *ssa = scdf->ssa;
DEBUG_PRINT("Start SCDF solve (%s)\n", name);
while (!zend_bitset_empty(scdf->instr_worklist, scdf->instr_worklist_len)
|| !zend_bitset_empty(scdf->phi_var_worklist, scdf->phi_var_worklist_len)
|| !zend_bitset_empty(scdf->block_worklist, scdf->block_worklist_len)
) {
int i;
while ((i = zend_bitset_pop_first(scdf->phi_var_worklist, scdf->phi_var_worklist_len)) >= 0) {
zend_ssa_phi *phi = ssa->vars[i].definition_phi;
ZEND_ASSERT(phi);
if (zend_bitset_in(scdf->executable_blocks, phi->block)) {
scdf->handlers.visit_phi(scdf, phi);
}
}
while ((i = zend_bitset_pop_first(scdf->instr_worklist, scdf->instr_worklist_len)) >= 0) {
int block_num = ssa->cfg.map[i];
if (zend_bitset_in(scdf->executable_blocks, block_num)) {
zend_basic_block *block = &ssa->cfg.blocks[block_num];
zend_op *opline = &scdf->op_array->opcodes[i];
zend_ssa_op *ssa_op = &ssa->ops[i];
if (opline->opcode == ZEND_OP_DATA) {
opline--;
ssa_op--;
}
scdf->handlers.visit_instr(scdf, opline, ssa_op);
if (i == block->start + block->len - 1) {
if (block->successors_count == 1) {
scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
} else if (block->successors_count > 1) {
scdf->handlers.mark_feasible_successors(scdf, block_num, block, opline, ssa_op);
}
}
}
}
while ((i = zend_bitset_pop_first(scdf->block_worklist, scdf->block_worklist_len)) >= 0) {
/* This block is now live. Interpret phis and instructions in it. */
zend_basic_block *block = &ssa->cfg.blocks[i];
zend_ssa_block *ssa_block = &ssa->blocks[i];
DEBUG_PRINT("Pop block %d from worklist\n", i);
zend_bitset_incl(scdf->executable_blocks, i);
{
zend_ssa_phi *phi;
for (phi = ssa_block->phis; phi; phi = phi->next) {
zend_bitset_excl(scdf->phi_var_worklist, phi->ssa_var);
scdf->handlers.visit_phi(scdf, phi);
}
}
if (block->len == 0) {
/* Zero length blocks don't have a last instruction that would normally do this */
scdf_mark_edge_feasible(scdf, i, block->successors[0]);
} else {
zend_op *opline = NULL;
int j, end = block->start + block->len;
for (j = block->start; j < end; j++) {
opline = &scdf->op_array->opcodes[j];
zend_bitset_excl(scdf->instr_worklist, j);
if (opline->opcode != ZEND_OP_DATA) {
scdf->handlers.visit_instr(scdf, opline, &ssa->ops[j]);
}
}
if (block->successors_count == 1) {
scdf_mark_edge_feasible(scdf, i, block->successors[0]);
} else if (block->successors_count > 1) {
ZEND_ASSERT(opline && "Should have opline in non-empty block");
if (opline->opcode == ZEND_OP_DATA) {
opline--;
j--;
}
scdf->handlers.mark_feasible_successors(scdf, i, block, opline, &ssa->ops[j-1]);
}
}
}
}
}
/* If a live range starts in a reachable block and ends in an unreachable block, we should
* not eliminate the latter. While it cannot be reached, the FREE opcode of the loop var
* is necessary for the correctness of temporary compaction. */
static bool kept_alive_by_loop_var_free(scdf_ctx *scdf, uint32_t block_idx) {
uint32_t i;
const zend_op_array *op_array = scdf->op_array;
const zend_cfg *cfg = &scdf->ssa->cfg;
const zend_basic_block *block = &cfg->blocks[block_idx];
if (!(cfg->flags & ZEND_FUNC_FREE_LOOP_VAR)) {
return 0;
}
for (i = block->start; i < block->start + block->len; i++) {
zend_op *opline = &op_array->opcodes[i];
if (zend_optimizer_is_loop_var_free(opline)) {
int ssa_var = scdf->ssa->ops[i].op1_use;
if (ssa_var >= 0) {
int op_num = scdf->ssa->vars[ssa_var].definition;
uint32_t def_block;
ZEND_ASSERT(op_num >= 0);
def_block = cfg->map[op_num];
if (zend_bitset_in(scdf->executable_blocks, def_block)) {
return 1;
}
}
}
}
return 0;
}
/* Removes unreachable blocks. This will remove both the instructions (and phis) in the
* blocks, as well as remove them from the successor / predecessor lists and mark them
* unreachable. Blocks already marked unreachable are not removed. */
int scdf_remove_unreachable_blocks(scdf_ctx *scdf) {
zend_ssa *ssa = scdf->ssa;
int i;
int removed_ops = 0;
for (i = 0; i < ssa->cfg.blocks_count; i++) {
if (!zend_bitset_in(scdf->executable_blocks, i)
&& (ssa->cfg.blocks[i].flags & ZEND_BB_REACHABLE)
&& !kept_alive_by_loop_var_free(scdf, i)) {
removed_ops += ssa->cfg.blocks[i].len;
zend_ssa_remove_block(scdf->op_array, ssa, i);
}
}
return removed_ops;
}
-99
View File
@@ -1,99 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Nikita Popov <nikic@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef _SCDF_H
#define _SCDF_H
#include "zend_bitset.h"
typedef struct _scdf_ctx {
zend_op_array *op_array;
zend_ssa *ssa;
zend_bitset instr_worklist;
/* Represent phi-instructions through the defining var */
zend_bitset phi_var_worklist;
zend_bitset block_worklist;
zend_bitset executable_blocks;
/* 1 bit per edge, see scdf_edge(cfg, from, to) */
zend_bitset feasible_edges;
uint32_t instr_worklist_len;
uint32_t phi_var_worklist_len;
uint32_t block_worklist_len;
struct {
void (*visit_instr)(
struct _scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op);
void (*visit_phi)(
struct _scdf_ctx *scdf, zend_ssa_phi *phi);
void (*mark_feasible_successors)(
struct _scdf_ctx *scdf, int block_num, zend_basic_block *block,
zend_op *opline, zend_ssa_op *ssa_op);
} handlers;
} scdf_ctx;
void scdf_init(zend_optimizer_ctx *ctx, scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa);
void scdf_solve(scdf_ctx *scdf, const char *name);
int scdf_remove_unreachable_blocks(scdf_ctx *scdf);
/* Add uses to worklist */
static inline void scdf_add_to_worklist(scdf_ctx *scdf, int var_num) {
zend_ssa *ssa = scdf->ssa;
zend_ssa_var *var = &ssa->vars[var_num];
int use;
zend_ssa_phi *phi;
FOREACH_USE(var, use) {
zend_bitset_incl(scdf->instr_worklist, use);
} FOREACH_USE_END();
FOREACH_PHI_USE(var, phi) {
zend_bitset_incl(scdf->phi_var_worklist, phi->ssa_var);
} FOREACH_PHI_USE_END();
}
/* This should usually not be necessary, however it's used for type narrowing. */
static inline void scdf_add_def_to_worklist(scdf_ctx *scdf, int var_num) {
zend_ssa_var *var = &scdf->ssa->vars[var_num];
if (var->definition >= 0) {
zend_bitset_incl(scdf->instr_worklist, var->definition);
} else if (var->definition_phi) {
zend_bitset_incl(scdf->phi_var_worklist, var_num);
}
}
static inline uint32_t scdf_edge(zend_cfg *cfg, int from, int to) {
zend_basic_block *to_block = cfg->blocks + to;
int i;
for (i = 0; i < to_block->predecessors_count; i++) {
uint32_t edge = to_block->predecessor_offset + i;
if (cfg->predecessors[edge] == from) {
return edge;
}
}
ZEND_UNREACHABLE();
}
static inline bool scdf_is_edge_feasible(scdf_ctx *scdf, int from, int to) {
uint32_t edge = scdf_edge(&scdf->ssa->cfg, from, to);
return zend_bitset_in(scdf->feasible_edges, edge);
}
void scdf_mark_edge_feasible(scdf_ctx *scdf, int from, int to);
#endif
-378
View File
@@ -1,378 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, SSA validation |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Nikita Popov <nikic@php.net> |
+----------------------------------------------------------------------+
*/
#include "Optimizer/zend_optimizer_internal.h"
/* The ssa_verify_integrity() function ensures that that certain invariants of the SSA form and
* CFG are upheld and prints messages to stderr if this is not the case. */
static inline bool is_in_use_chain(zend_ssa *ssa, int var, int check) {
int use;
FOREACH_USE(&ssa->vars[var], use) {
if (use == check) {
return 1;
}
} FOREACH_USE_END();
return 0;
}
static inline bool is_in_phi_use_chain(zend_ssa *ssa, int var, zend_ssa_phi *check) {
zend_ssa_phi *phi;
FOREACH_PHI_USE(&ssa->vars[var], phi) {
if (phi == check) {
return 1;
}
} FOREACH_PHI_USE_END();
return 0;
}
static inline bool is_used_by_op(zend_ssa *ssa, int op, int check) {
zend_ssa_op *ssa_op = &ssa->ops[op];
return (ssa_op->op1_use == check)
|| (ssa_op->op2_use == check)
|| (ssa_op->result_use == check);
}
static inline bool is_defined_by_op(zend_ssa *ssa, int op, int check) {
zend_ssa_op *ssa_op = &ssa->ops[op];
return (ssa_op->op1_def == check)
|| (ssa_op->op2_def == check)
|| (ssa_op->result_def == check);
}
static inline bool is_in_phi_sources(zend_ssa *ssa, zend_ssa_phi *phi, int check) {
int source;
FOREACH_PHI_SOURCE(phi, source) {
if (source == check) {
return 1;
}
} FOREACH_PHI_SOURCE_END();
return 0;
}
static inline bool is_in_predecessors(zend_cfg *cfg, zend_basic_block *block, int check) {
int i, *predecessors = &cfg->predecessors[block->predecessor_offset];
for (i = 0; i < block->predecessors_count; i++) {
if (predecessors[i] == check) {
return 1;
}
}
return 0;
}
static inline bool is_in_successors(zend_basic_block *block, int check) {
int s;
for (s = 0; s < block->successors_count; s++) {
if (block->successors[s] == check) {
return 1;
}
}
return 0;
}
static inline bool is_var_type(zend_uchar type) {
return (type & (IS_CV|IS_VAR|IS_TMP_VAR)) != 0;
}
#define FAIL(...) do { \
if (status == SUCCESS) { \
fprintf(stderr, "\nIn function %s::%s (%s):\n", \
op_array->scope ? ZSTR_VAL(op_array->scope->name) : "", \
op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}", extra); \
} \
fprintf(stderr, __VA_ARGS__); \
status = FAILURE; \
} while (0)
#define VARFMT "%d (%s%s)"
#define VAR(i) \
(i), (ssa->vars[i].var < op_array->last_var ? "CV $" : "TMP"), \
(ssa->vars[i].var < op_array->last_var ? ZSTR_VAL(op_array->vars[ssa->vars[i].var]) : "")
#define INSTRFMT "%d (%s)"
#define INSTR(i) \
(i), (zend_get_opcode_name(op_array->opcodes[i].opcode))
int ssa_verify_integrity(zend_op_array *op_array, zend_ssa *ssa, const char *extra) {
zend_cfg *cfg = &ssa->cfg;
zend_ssa_phi *phi;
int i, status = SUCCESS;
/* Vars */
for (i = 0; i < ssa->vars_count; i++) {
zend_ssa_var *var = &ssa->vars[i];
int use, c;
uint32_t type = ssa->var_info[i].type;
if (var->definition < 0 && !var->definition_phi && i > op_array->last_var) {
if (var->use_chain >= 0) {
FAIL("var " VARFMT " without def has op uses\n", VAR(i));
}
if (var->phi_use_chain) {
FAIL("var " VARFMT " without def has phi uses\n", VAR(i));
}
}
if (var->definition >= 0 && var->definition_phi) {
FAIL("var " VARFMT " has both def and def_phi\n", VAR(i));
}
if (var->definition >= 0) {
if (!is_defined_by_op(ssa, var->definition, i)) {
FAIL("var " VARFMT " not defined by op " INSTRFMT "\n",
VAR(i), INSTR(var->definition));
}
}
if (var->definition_phi) {
if (var->definition_phi->ssa_var != i) {
FAIL("var " VARFMT " not defined by given phi\n", VAR(i));
}
}
c = 0;
FOREACH_USE(var, use) {
if (++c > 10000) {
FAIL("cycle in uses of " VARFMT "\n", VAR(i));
return status;
}
if (!is_used_by_op(ssa, use, i)) {
fprintf(stderr, "var " VARFMT " not in uses of op %d\n", VAR(i), use);
}
} FOREACH_USE_END();
c = 0;
FOREACH_PHI_USE(var, phi) {
if (++c > 10000) {
FAIL("cycle in phi uses of " VARFMT "\n", VAR(i));
return status;
}
if (!is_in_phi_sources(ssa, phi, i)) {
FAIL("var " VARFMT " not in phi sources of %d\n", VAR(i), phi->ssa_var);
}
} FOREACH_PHI_USE_END();
if ((type & MAY_BE_ARRAY_KEY_ANY) && !(type & MAY_BE_ARRAY_OF_ANY)) {
FAIL("var " VARFMT " has array key type but not value type\n", VAR(i));
}
if ((type & MAY_BE_ARRAY_OF_ANY) && !(type & MAY_BE_ARRAY_KEY_ANY)) {
FAIL("var " VARFMT " has array value type but not key type\n", VAR(i));
}
}
/* Instructions */
FOREACH_INSTR_NUM(i) {
zend_ssa_op *ssa_op = &ssa->ops[i];
zend_op *opline = &op_array->opcodes[i];
if (is_var_type(opline->op1_type)) {
if (ssa_op->op1_use < 0 && ssa_op->op1_def < 0) {
FAIL("var op1 of " INSTRFMT " does not use/def an ssa var\n", INSTR(i));
}
} else {
if (ssa_op->op1_use >= 0 || ssa_op->op1_def >= 0) {
FAIL("non-var op1 of " INSTRFMT " uses or defs an ssa var\n", INSTR(i));
}
}
if (is_var_type(opline->op2_type)) {
if (ssa_op->op2_use < 0 && ssa_op->op2_def < 0) {
FAIL("var op2 of " INSTRFMT " does not use/def an ssa var\n", INSTR(i));
}
} else {
if (ssa_op->op2_use >= 0 || ssa_op->op2_def >= 0) {
FAIL("non-var op2 of " INSTRFMT " uses or defs an ssa var\n", INSTR(i));
}
}
if (is_var_type(opline->result_type)) {
if (ssa_op->result_use < 0 && ssa_op->result_def < 0) {
FAIL("var result of " INSTRFMT " does not use/def an ssa var\n", INSTR(i));
}
} else {
if (ssa_op->result_use >= 0 || ssa_op->result_def >= 0) {
FAIL("non-var result of " INSTRFMT " uses or defs an ssa var\n", INSTR(i));
}
}
if (ssa_op->op1_use >= 0) {
if (ssa_op->op1_use >= ssa->vars_count) {
FAIL("op1 use %d out of range\n", ssa_op->op1_use);
}
if (!is_in_use_chain(ssa, ssa_op->op1_use, i)) {
FAIL("op1 use of " VARFMT " in " INSTRFMT " not in use chain\n",
VAR(ssa_op->op1_use), INSTR(i));
}
if (VAR_NUM(opline->op1.var) != ssa->vars[ssa_op->op1_use].var) {
FAIL("op1 use of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->op1_use), VAR_NUM(opline->op1.var), INSTR(i));
}
}
if (ssa_op->op2_use >= 0) {
if (ssa_op->op2_use >= ssa->vars_count) {
FAIL("op2 use %d out of range\n", ssa_op->op2_use);
}
if (!is_in_use_chain(ssa, ssa_op->op2_use, i)) {
FAIL("op2 use of " VARFMT " in " INSTRFMT " not in use chain\n",
VAR(ssa_op->op2_use), INSTR(i));
}
if (VAR_NUM(opline->op2.var) != ssa->vars[ssa_op->op2_use].var) {
FAIL("op2 use of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->op2_use), VAR_NUM(opline->op2.var), INSTR(i));
}
}
if (ssa_op->result_use >= 0) {
if (ssa_op->result_use >= ssa->vars_count) {
FAIL("result use %d out of range\n", ssa_op->result_use);
}
if (!is_in_use_chain(ssa, ssa_op->result_use, i)) {
FAIL("result use of " VARFMT " in " INSTRFMT " not in use chain\n",
VAR(ssa_op->result_use), INSTR(i));
}
if (VAR_NUM(opline->result.var) != ssa->vars[ssa_op->result_use].var) {
FAIL("result use of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->result_use), VAR_NUM(opline->result.var), INSTR(i));
}
}
if (ssa_op->op1_def >= 0) {
if (ssa_op->op1_def >= ssa->vars_count) {
FAIL("op1 def %d out of range\n", ssa_op->op1_def);
}
if (ssa->vars[ssa_op->op1_def].definition != i) {
FAIL("op1 def of " VARFMT " in " INSTRFMT " invalid\n",
VAR(ssa_op->op1_def), INSTR(i));
}
if (VAR_NUM(opline->op1.var) != ssa->vars[ssa_op->op1_def].var) {
FAIL("op1 def of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->op1_def), VAR_NUM(opline->op1.var), INSTR(i));
}
}
if (ssa_op->op2_def >= 0) {
if (ssa_op->op2_def >= ssa->vars_count) {
FAIL("op2 def %d out of range\n", ssa_op->op2_def);
}
if (ssa->vars[ssa_op->op2_def].definition != i) {
FAIL("op2 def of " VARFMT " in " INSTRFMT " invalid\n",
VAR(ssa_op->op2_def), INSTR(i));
}
if (VAR_NUM(opline->op2.var) != ssa->vars[ssa_op->op2_def].var) {
FAIL("op2 def of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->op2_def), VAR_NUM(opline->op2.var), INSTR(i));
}
}
if (ssa_op->result_def >= 0) {
if (ssa_op->result_def >= ssa->vars_count) {
FAIL("result def %d out of range\n", ssa_op->result_def);
}
if (ssa->vars[ssa_op->result_def].definition != i) {
FAIL("result def of " VARFMT " in " INSTRFMT " invalid\n",
VAR(ssa_op->result_def), INSTR(i));
}
if (VAR_NUM(opline->result.var) != ssa->vars[ssa_op->result_def].var) {
FAIL("result def of " VARFMT " does not match op %d of " INSTRFMT "\n",
VAR(ssa_op->result_def), VAR_NUM(opline->result.var), INSTR(i));
}
}
} FOREACH_INSTR_NUM_END();
/* Phis */
FOREACH_PHI(phi) {
unsigned num_sources = NUM_PHI_SOURCES(phi);
for (i = 0; i < num_sources; i++) {
int source = phi->sources[i];
if (source < 0) {
FAIL(VARFMT " negative source\n", VAR(phi->ssa_var));
}
if (!is_in_phi_use_chain(ssa, source, phi)) {
FAIL(VARFMT " not in phi use chain of %d\n", VAR(phi->ssa_var), source);
}
if (ssa->vars[source].var != ssa->vars[phi->ssa_var].var) {
FAIL(VARFMT " source of phi for " VARFMT "\n", VAR(source), VAR(phi->ssa_var));
}
if (phi->use_chains[i]) {
int j;
for (j = i + 1; j < num_sources; j++) {
if (phi->sources[j] == source && phi->use_chains[j]) {
FAIL("use chain for source " VARFMT " of phi " VARFMT
" at %d despite earlier use\n", VAR(source), VAR(phi->ssa_var), j);
}
}
}
}
if (ssa->vars[phi->ssa_var].definition_phi != phi) {
FAIL(VARFMT " does not define this phi\n", VAR(phi->ssa_var));
}
} FOREACH_PHI_END();
/* Blocks */
for (i = 0; i < cfg->blocks_count; i++) {
zend_basic_block *block = &cfg->blocks[i];
int *predecessors = &cfg->predecessors[block->predecessor_offset];
int s, j;
if (i != 0 && block->start < (block-1)->start + (block-1)->len) {
FAIL("Block %d start %d smaller previous end %d\n",
i, block->start, (block-1)->start + (block-1)->len);
}
if (i != cfg->blocks_count-1 && block->start + block->len > (block+1)->start) {
FAIL("Block %d end %d greater next start %d\n",
i, block->start + block->len, (block+1)->start);
}
for (j = block->start; j < block->start + block->len; j++) {
if (cfg->map[j] != i) {
FAIL("Instr " INSTRFMT " not associated with block %d\n", INSTR(j), i);
}
}
if (!(block->flags & ZEND_BB_REACHABLE)) {
if (ssa->blocks[i].phis) {
FAIL("Unreachable block %d has phis\n", i);
}
continue;
}
for (s = 0; s < block->successors_count; s++) {
zend_basic_block *next_block;
if (block->successors[s] < 0) {
FAIL("Successor number %d of %d negative", s, i);
}
next_block = &cfg->blocks[block->successors[s]];
if (!(next_block->flags & ZEND_BB_REACHABLE)) {
FAIL("Successor %d of %d not reachable\n", block->successors[s], i);
}
if (!is_in_predecessors(cfg, next_block, i)) {
FAIL("Block %d predecessors missing %d\n", block->successors[s], i);
}
}
for (j = 0; j < block->predecessors_count; j++) {
if (predecessors[j] >= 0) {
int k;
zend_basic_block *prev_block = &cfg->blocks[predecessors[j]];
if (!(prev_block->flags & ZEND_BB_REACHABLE)) {
FAIL("Predecessor %d of %d not reachable\n", predecessors[j], i);
}
if (!is_in_successors(prev_block, i)) {
FAIL("Block %d successors missing %d\n", predecessors[j], i);
}
for (k = 0; k < block->predecessors_count; k++) {
if (k != j && predecessors[k] == predecessors[j]) {
FAIL("Block %d has duplicate predecessor %d\n", i, predecessors[j]);
}
}
}
}
}
return status;
}
-273
View File
@@ -1,273 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "zend_compile.h"
#include "zend_extensions.h"
#include "Optimizer/zend_optimizer.h"
#include "zend_optimizer_internal.h"
#include "zend_inference.h"
#include "zend_call_graph.h"
#include "zend_func_info.h"
#include "zend_inference.h"
#include "zend_call_graph.h"
static void zend_op_array_calc(zend_op_array *op_array, void *context)
{
zend_call_graph *call_graph = context;
call_graph->op_arrays_count++;
}
static void zend_op_array_collect(zend_op_array *op_array, void *context)
{
zend_call_graph *call_graph = context;
zend_func_info *func_info = call_graph->func_infos + call_graph->op_arrays_count;
ZEND_SET_FUNC_INFO(op_array, func_info);
call_graph->op_arrays[call_graph->op_arrays_count] = op_array;
func_info->num = call_graph->op_arrays_count;
call_graph->op_arrays_count++;
}
ZEND_API int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info)
{
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
zend_function *func;
zend_call_info *call_info;
int call = 0;
zend_call_info **call_stack;
ALLOCA_FLAG(use_heap);
bool is_prototype;
call_stack = do_alloca((op_array->last / 2) * sizeof(zend_call_info*), use_heap);
call_info = NULL;
while (opline != end) {
switch (opline->opcode) {
case ZEND_INIT_FCALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL:
call_stack[call] = call_info;
func = zend_optimizer_get_called_func(
script, op_array, opline, &is_prototype);
if (func) {
call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1)));
call_info->caller_op_array = op_array;
call_info->caller_init_opline = opline;
call_info->caller_call_opline = NULL;
call_info->callee_func = func;
call_info->num_args = opline->extended_value;
call_info->next_callee = func_info->callee_info;
call_info->is_prototype = is_prototype;
func_info->callee_info = call_info;
if (build_flags & ZEND_CALL_TREE) {
call_info->next_caller = NULL;
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
call_info->next_caller = NULL;
} else {
zend_func_info *callee_func_info = ZEND_FUNC_INFO(&func->op_array);
if (callee_func_info) {
call_info->next_caller = callee_func_info->caller_info;
callee_func_info->caller_info = call_info;
} else {
call_info->next_caller = NULL;
}
}
} else {
call_info = NULL;
}
call++;
break;
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_NEW:
case ZEND_INIT_USER_CALL:
call_stack[call] = call_info;
call_info = NULL;
call++;
break;
case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
func_info->flags |= ZEND_FUNC_HAS_CALLS;
if (call_info) {
call_info->caller_call_opline = opline;
}
call--;
call_info = call_stack[call];
break;
case ZEND_SEND_VAL:
case ZEND_SEND_VAR:
case ZEND_SEND_VAL_EX:
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
case ZEND_SEND_REF:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_USER:
if (call_info) {
if (opline->op2_type == IS_CONST) {
call_info->named_args = 1;
break;
}
uint32_t num = opline->op2.num;
if (num > 0) {
num--;
}
call_info->arg_info[num].opline = opline;
}
break;
case ZEND_SEND_ARRAY:
case ZEND_SEND_UNPACK:
if (call_info) {
call_info->send_unpack = 1;
}
break;
case ZEND_EXIT:
/* In this case the DO_CALL opcode may have been dropped
* and caller_call_opline will be NULL. */
break;
}
opline++;
}
free_alloca(call_stack, use_heap);
return SUCCESS;
}
static int zend_is_indirectly_recursive(zend_op_array *root, zend_op_array *op_array, zend_bitset visited)
{
zend_func_info *func_info;
zend_call_info *call_info;
int ret = 0;
if (op_array == root) {
return 1;
}
func_info = ZEND_FUNC_INFO(op_array);
if (zend_bitset_in(visited, func_info->num)) {
return 0;
}
zend_bitset_incl(visited, func_info->num);
call_info = func_info->caller_info;
while (call_info) {
if (zend_is_indirectly_recursive(root, call_info->caller_op_array, visited)) {
call_info->recursive = 1;
ret = 1;
}
call_info = call_info->next_caller;
}
return ret;
}
static void zend_analyze_recursion(zend_call_graph *call_graph)
{
zend_op_array *op_array;
zend_func_info *func_info;
zend_call_info *call_info;
int i;
int set_len = zend_bitset_len(call_graph->op_arrays_count);
zend_bitset visited;
ALLOCA_FLAG(use_heap);
visited = ZEND_BITSET_ALLOCA(set_len, use_heap);
for (i = 0; i < call_graph->op_arrays_count; i++) {
op_array = call_graph->op_arrays[i];
func_info = call_graph->func_infos + i;
call_info = func_info->caller_info;
for (; call_info; call_info = call_info->next_caller) {
if (call_info->is_prototype) {
/* Might be calling an overridden child method and not actually recursive. */
continue;
}
if (call_info->caller_op_array == op_array) {
call_info->recursive = 1;
func_info->flags |= ZEND_FUNC_RECURSIVE | ZEND_FUNC_RECURSIVE_DIRECTLY;
} else {
memset(visited, 0, sizeof(zend_ulong) * set_len);
if (zend_is_indirectly_recursive(op_array, call_info->caller_op_array, visited)) {
call_info->recursive = 1;
func_info->flags |= ZEND_FUNC_RECURSIVE | ZEND_FUNC_RECURSIVE_INDIRECTLY;
}
}
}
}
free_alloca(visited, use_heap);
}
static void zend_sort_op_arrays(zend_call_graph *call_graph)
{
(void) call_graph;
// TODO: perform topological sort of cyclic call graph
}
ZEND_API int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
{
call_graph->op_arrays_count = 0;
zend_foreach_op_array(script, zend_op_array_calc, call_graph);
call_graph->op_arrays = (zend_op_array**)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_op_array*));
call_graph->func_infos = (zend_func_info*)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_func_info));
call_graph->op_arrays_count = 0;
zend_foreach_op_array(script, zend_op_array_collect, call_graph);
return SUCCESS;
}
/* }}} */
ZEND_API void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
{
int i;
for (i = 0; i < call_graph->op_arrays_count; i++) {
zend_analyze_calls(arena, script, 0, call_graph->op_arrays[i], call_graph->func_infos + i);
}
zend_analyze_recursion(call_graph);
zend_sort_op_arrays(call_graph);
}
/* }}} */
ZEND_API zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, const zend_op_array *op_array) /* {{{ */
{
zend_call_info **map, *call;
if (!info->callee_info) {
/* Don't build call map if function contains no calls */
return NULL;
}
map = zend_arena_calloc(arena, sizeof(zend_call_info *), op_array->last);
for (call = info->callee_info; call; call = call->next_callee) {
int i;
map[call->caller_init_opline - op_array->opcodes] = call;
if (call->caller_call_opline) {
map[call->caller_call_opline - op_array->opcodes] = call;
}
for (i = 0; i < call->num_args; i++) {
if (call->arg_info[i].opline) {
map[call->arg_info[i].opline - op_array->opcodes] = call;
}
}
}
return map;
}
/* }}} */
-70
View File
@@ -1,70 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_CALL_GRAPH_H
#define ZEND_CALL_GRAPH_H
#include "zend_ssa.h"
#include "zend_func_info.h"
#include "zend_optimizer.h"
typedef struct _zend_send_arg_info {
zend_op *opline;
} zend_send_arg_info;
struct _zend_call_info {
zend_op_array *caller_op_array;
zend_op *caller_init_opline;
zend_op *caller_call_opline;
zend_function *callee_func;
zend_call_info *next_caller;
zend_call_info *next_callee;
bool recursive;
bool send_unpack; /* Parameters passed by SEND_UNPACK or SEND_ARRAY */
bool named_args; /* Function has named arguments */
bool is_prototype; /* An overridden child method may be called */
int num_args;
zend_send_arg_info arg_info[1];
};
struct _zend_func_info {
int num;
uint32_t flags;
zend_ssa ssa; /* Static Single Assignment Form */
zend_call_info *caller_info; /* where this function is called from */
zend_call_info *callee_info; /* which functions are called from this one */
zend_call_info **call_map; /* Call info associated with init/call/send opnum */
zend_ssa_var_info return_info;
};
typedef struct _zend_call_graph {
int op_arrays_count;
zend_op_array **op_arrays;
zend_func_info *func_infos;
} zend_call_graph;
BEGIN_EXTERN_C()
ZEND_API int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
ZEND_API void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
ZEND_API zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, const zend_op_array *op_array);
ZEND_API int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
END_EXTERN_C()
#endif /* ZEND_CALL_GRAPH_H */
-912
View File
@@ -1,912 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "zend_compile.h"
#include "zend_cfg.h"
#include "zend_func_info.h"
#include "zend_worklist.h"
#include "zend_optimizer.h"
#include "zend_optimizer_internal.h"
#include "zend_sort.h"
static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
{
zend_basic_block *blocks = cfg->blocks;
while (1) {
int i;
b->flags |= ZEND_BB_REACHABLE;
if (b->successors_count == 0) {
b->flags |= ZEND_BB_EXIT;
return;
}
for (i = 0; i < b->successors_count; i++) {
zend_basic_block *succ = blocks + b->successors[i];
if (b->len != 0) {
zend_uchar opcode = opcodes[b->start + b->len - 1].opcode;
if (b->successors_count == 1) {
if (opcode == ZEND_JMP) {
succ->flags |= ZEND_BB_TARGET;
} else {
succ->flags |= ZEND_BB_FOLLOW;
if ((cfg->flags & ZEND_CFG_STACKLESS)) {
if (opcode == ZEND_INCLUDE_OR_EVAL ||
opcode == ZEND_GENERATOR_CREATE ||
opcode == ZEND_YIELD ||
opcode == ZEND_YIELD_FROM ||
opcode == ZEND_DO_FCALL ||
opcode == ZEND_DO_UCALL ||
opcode == ZEND_DO_FCALL_BY_NAME) {
succ->flags |= ZEND_BB_ENTRY;
}
}
if ((cfg->flags & ZEND_CFG_RECV_ENTRY)) {
if (opcode == ZEND_RECV ||
opcode == ZEND_RECV_INIT) {
succ->flags |= ZEND_BB_RECV_ENTRY;
}
}
}
} else if (b->successors_count == 2) {
if (i == 0 || opcode == ZEND_JMPZNZ) {
succ->flags |= ZEND_BB_TARGET;
} else {
succ->flags |= ZEND_BB_FOLLOW;
}
} else {
ZEND_ASSERT(
opcode == ZEND_SWITCH_LONG
|| opcode == ZEND_SWITCH_STRING
|| opcode == ZEND_MATCH
);
if (i == b->successors_count - 1) {
succ->flags |= ZEND_BB_FOLLOW | ZEND_BB_TARGET;
} else {
succ->flags |= ZEND_BB_TARGET;
}
}
} else {
succ->flags |= ZEND_BB_FOLLOW;
}
if (i == b->successors_count - 1) {
/* Tail call optimization */
if (succ->flags & ZEND_BB_REACHABLE) {
return;
}
b = succ;
break;
} else {
/* Recursively check reachability */
if (!(succ->flags & ZEND_BB_REACHABLE)) {
zend_mark_reachable(opcodes, cfg, succ);
}
}
}
}
}
/* }}} */
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
{
zend_basic_block *blocks = cfg->blocks;
blocks[start].flags = ZEND_BB_START;
zend_mark_reachable(op_array->opcodes, cfg, blocks + start);
if (op_array->last_try_catch) {
zend_basic_block *b;
int j, changed;
uint32_t *block_map = cfg->map;
do {
changed = 0;
/* Add exception paths */
for (j = 0; j < op_array->last_try_catch; j++) {
/* check for jumps into the middle of try block */
b = blocks + block_map[op_array->try_catch_array[j].try_op];
if (!(b->flags & ZEND_BB_REACHABLE)) {
zend_basic_block *end;
if (op_array->try_catch_array[j].catch_op) {
end = blocks + block_map[op_array->try_catch_array[j].catch_op];
while (b != end) {
if (b->flags & ZEND_BB_REACHABLE) {
op_array->try_catch_array[j].try_op = b->start;
break;
}
b++;
}
}
b = blocks + block_map[op_array->try_catch_array[j].try_op];
if (!(b->flags & ZEND_BB_REACHABLE)) {
if (op_array->try_catch_array[j].finally_op) {
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
while (b != end) {
if (b->flags & ZEND_BB_REACHABLE) {
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
break;
}
b++;
}
}
}
}
b = blocks + block_map[op_array->try_catch_array[j].try_op];
if (b->flags & ZEND_BB_REACHABLE) {
b->flags |= ZEND_BB_TRY;
if (op_array->try_catch_array[j].catch_op) {
b = blocks + block_map[op_array->try_catch_array[j].catch_op];
b->flags |= ZEND_BB_CATCH;
if (!(b->flags & ZEND_BB_REACHABLE)) {
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, b);
}
}
if (op_array->try_catch_array[j].finally_op) {
b = blocks + block_map[op_array->try_catch_array[j].finally_op];
b->flags |= ZEND_BB_FINALLY;
if (!(b->flags & ZEND_BB_REACHABLE)) {
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, b);
}
}
if (op_array->try_catch_array[j].finally_end) {
b = blocks + block_map[op_array->try_catch_array[j].finally_end];
b->flags |= ZEND_BB_FINALLY_END;
if (!(b->flags & ZEND_BB_REACHABLE)) {
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, b);
}
}
} else {
if (op_array->try_catch_array[j].catch_op) {
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
}
if (op_array->try_catch_array[j].finally_op) {
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
}
if (op_array->try_catch_array[j].finally_end) {
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
}
}
}
} while (changed);
}
if (cfg->flags & ZEND_FUNC_FREE_LOOP_VAR) {
zend_basic_block *b;
int j;
uint32_t *block_map = cfg->map;
/* Mark blocks that are unreachable, but free a loop var created in a reachable block. */
for (b = blocks; b < blocks + cfg->blocks_count; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
continue;
}
for (j = b->start; j < b->start + b->len; j++) {
zend_op *opline = &op_array->opcodes[j];
if (zend_optimizer_is_loop_var_free(opline)) {
zend_op *def_opline = zend_optimizer_get_loop_var_def(op_array, opline);
if (def_opline) {
uint32_t def_block = block_map[def_opline - op_array->opcodes];
if (blocks[def_block].flags & ZEND_BB_REACHABLE) {
b->flags |= ZEND_BB_UNREACHABLE_FREE;
break;
}
}
}
}
}
}
}
/* }}} */
void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */
{
zend_basic_block *blocks = cfg->blocks;
int i;
int start = 0;
for (i = 0; i < cfg->blocks_count; i++) {
if (blocks[i].flags & ZEND_BB_REACHABLE) {
start = i;
i++;
break;
}
}
/* clear all flags */
for (i = 0; i < cfg->blocks_count; i++) {
blocks[i].flags = 0;
}
zend_mark_reachable_blocks(op_array, cfg, start);
}
/* }}} */
static void initialize_block(zend_basic_block *block) {
block->flags = 0;
block->successors = block->successors_storage;
block->successors_count = 0;
block->predecessors_count = 0;
block->predecessor_offset = -1;
block->idom = -1;
block->loop_header = -1;
block->level = -1;
block->children = -1;
block->next_child = -1;
}
#define BB_START(i) do { \
if (!block_map[i]) { blocks_count++;} \
block_map[i]++; \
} while (0)
ZEND_API int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
{
uint32_t flags = 0;
uint32_t i;
int j;
uint32_t *block_map;
zend_function *fn;
int blocks_count = 0;
zend_basic_block *blocks;
zval *zv;
bool extra_entry_block = 0;
cfg->flags = build_flags & (ZEND_CFG_STACKLESS|ZEND_CFG_RECV_ENTRY);
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
BB_START(0);
for (i = 0; i < op_array->last; i++) {
zend_op *opline = op_array->opcodes + i;
switch (opline->opcode) {
case ZEND_RECV:
case ZEND_RECV_INIT:
if (build_flags & ZEND_CFG_RECV_ENTRY) {
BB_START(i + 1);
}
break;
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_MATCH_ERROR:
case ZEND_VERIFY_NEVER_TYPE:
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_THROW:
/* Don't treat THROW as terminator if it's used in expression context,
* as we may lose live ranges when eliminating unreachable code. */
if (opline->extended_value != ZEND_THROW_IS_EXPR && i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_INCLUDE_OR_EVAL:
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
ZEND_FALLTHROUGH;
case ZEND_GENERATOR_CREATE:
case ZEND_YIELD:
case ZEND_YIELD_FROM:
if (build_flags & ZEND_CFG_STACKLESS) {
BB_START(i + 1);
}
break;
case ZEND_DO_FCALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
flags |= ZEND_FUNC_HAS_CALLS;
if (build_flags & ZEND_CFG_STACKLESS) {
BB_START(i + 1);
}
break;
case ZEND_DO_ICALL:
flags |= ZEND_FUNC_HAS_CALLS;
break;
case ZEND_INIT_FCALL:
case ZEND_INIT_NS_FCALL_BY_NAME:
zv = CRT_CONSTANT(opline->op2);
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
/* The third literal is the lowercased unqualified name */
zv += 2;
}
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
if (fn->type == ZEND_INTERNAL_FUNCTION) {
flags |= zend_optimizer_classify_function(
Z_STR_P(zv), opline->extended_value);
}
}
break;
case ZEND_FAST_CALL:
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
BB_START(i + 1);
break;
case ZEND_FAST_RET:
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_JMP:
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_JMPZNZ:
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
case ZEND_JMP_NULL:
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
BB_START(i + 1);
break;
case ZEND_CATCH:
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
}
BB_START(i + 1);
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
BB_START(i + 1);
break;
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
BB_START(i + 1);
break;
case ZEND_SWITCH_LONG:
case ZEND_SWITCH_STRING:
case ZEND_MATCH:
{
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
zval *zv;
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
} ZEND_HASH_FOREACH_END();
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
BB_START(i + 1);
break;
}
case ZEND_FETCH_R:
case ZEND_FETCH_W:
case ZEND_FETCH_RW:
case ZEND_FETCH_FUNC_ARG:
case ZEND_FETCH_IS:
case ZEND_FETCH_UNSET:
case ZEND_UNSET_VAR:
case ZEND_ISSET_ISEMPTY_VAR:
if (opline->extended_value & ZEND_FETCH_LOCAL) {
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
!op_array->function_name) {
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
}
break;
case ZEND_FUNC_GET_ARGS:
flags |= ZEND_FUNC_VARARG;
break;
case ZEND_EXT_STMT:
flags |= ZEND_FUNC_HAS_EXTENDED_STMT;
break;
case ZEND_EXT_FCALL_BEGIN:
case ZEND_EXT_FCALL_END:
flags |= ZEND_FUNC_HAS_EXTENDED_FCALL;
break;
case ZEND_FREE:
if (opline->extended_value == ZEND_FREE_SWITCH) {
flags |= ZEND_FUNC_FREE_LOOP_VAR;
}
break;
case ZEND_FE_FREE:
flags |= ZEND_FUNC_FREE_LOOP_VAR;
break;
}
}
/* If the entry block has predecessors, we may need to split it */
if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS)
&& op_array->last > 0 && block_map[0] > 1) {
extra_entry_block = 1;
}
if (op_array->last_try_catch) {
for (j = 0; j < op_array->last_try_catch; j++) {
BB_START(op_array->try_catch_array[j].try_op);
if (op_array->try_catch_array[j].catch_op) {
BB_START(op_array->try_catch_array[j].catch_op);
}
if (op_array->try_catch_array[j].finally_op) {
BB_START(op_array->try_catch_array[j].finally_op);
}
if (op_array->try_catch_array[j].finally_end) {
BB_START(op_array->try_catch_array[j].finally_end);
}
}
}
blocks_count += extra_entry_block;
cfg->blocks_count = blocks_count;
/* Build CFG, Step 2: Build Array of Basic Blocks */
cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
blocks_count = -1;
if (extra_entry_block) {
initialize_block(&blocks[0]);
blocks[0].start = 0;
blocks[0].len = 0;
blocks_count++;
}
for (i = 0; i < op_array->last; i++) {
if (block_map[i]) {
if (blocks_count >= 0) {
blocks[blocks_count].len = i - blocks[blocks_count].start;
}
blocks_count++;
initialize_block(&blocks[blocks_count]);
blocks[blocks_count].start = i;
}
block_map[i] = blocks_count;
}
blocks[blocks_count].len = i - blocks[blocks_count].start;
blocks_count++;
/* Build CFG, Step 3: Calculate successors */
for (j = 0; j < blocks_count; j++) {
zend_basic_block *block = &blocks[j];
zend_op *opline;
if (block->len == 0) {
block->successors_count = 1;
block->successors[0] = j + 1;
continue;
}
opline = op_array->opcodes + block->start + block->len - 1;
switch (opline->opcode) {
case ZEND_FAST_RET:
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_THROW:
case ZEND_MATCH_ERROR:
case ZEND_VERIFY_NEVER_TYPE:
break;
case ZEND_JMP:
block->successors_count = 1;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
break;
case ZEND_JMPZNZ:
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
case ZEND_JMP_NULL:
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1;
break;
case ZEND_CATCH:
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1;
} else {
block->successors_count = 1;
block->successors[0] = j + 1;
}
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
block->successors_count = 2;
block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
block->successors[1] = j + 1;
break;
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1;
break;
case ZEND_FAST_CALL:
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
block->successors[1] = j + 1;
break;
case ZEND_SWITCH_LONG:
case ZEND_SWITCH_STRING:
case ZEND_MATCH:
{
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
zval *zv;
uint32_t s = 0;
block->successors_count = (opline->opcode == ZEND_MATCH ? 1 : 2) + zend_hash_num_elements(jumptable);
block->successors = zend_arena_calloc(arena, block->successors_count, sizeof(int));
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
} ZEND_HASH_FOREACH_END();
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
if (opline->opcode != ZEND_MATCH) {
block->successors[s++] = j + 1;
}
break;
}
default:
block->successors_count = 1;
block->successors[0] = j + 1;
break;
}
}
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
cfg->flags |= flags;
zend_mark_reachable_blocks(op_array, cfg, 0);
return SUCCESS;
}
/* }}} */
ZEND_API int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */
{
int j, s, edges;
zend_basic_block *b;
zend_basic_block *blocks = cfg->blocks;
zend_basic_block *end = blocks + cfg->blocks_count;
int *predecessors;
edges = 0;
for (b = blocks; b < end; b++) {
b->predecessors_count = 0;
}
for (b = blocks; b < end; b++) {
if (!(b->flags & ZEND_BB_REACHABLE)) {
b->successors_count = 0;
b->predecessors_count = 0;
} else {
for (s = 0; s < b->successors_count; s++) {
edges++;
blocks[b->successors[s]].predecessors_count++;
}
}
}
cfg->edges_count = edges;
cfg->predecessors = predecessors = (int*)zend_arena_calloc(arena, sizeof(int), edges);
edges = 0;
for (b = blocks; b < end; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
b->predecessor_offset = edges;
edges += b->predecessors_count;
b->predecessors_count = 0;
}
}
for (j = 0; j < cfg->blocks_count; j++) {
if (blocks[j].flags & ZEND_BB_REACHABLE) {
/* SWITCH_STRING/LONG may have few identical successors */
for (s = 0; s < blocks[j].successors_count; s++) {
int duplicate = 0;
int p;
for (p = 0; p < s; p++) {
if (blocks[j].successors[p] == blocks[j].successors[s]) {
duplicate = 1;
break;
}
}
if (!duplicate) {
zend_basic_block *b = blocks + blocks[j].successors[s];
predecessors[b->predecessor_offset + b->predecessors_count] = j;
b->predecessors_count++;
}
}
}
}
return SUCCESS;
}
/* }}} */
/* Computes a postorder numbering of the CFG */
static void compute_postnum_recursive(
int *postnum, int *cur, const zend_cfg *cfg, int block_num) /* {{{ */
{
int s;
zend_basic_block *block = &cfg->blocks[block_num];
if (postnum[block_num] != -1) {
return;
}
postnum[block_num] = -2; /* Marker for "currently visiting" */
for (s = 0; s < block->successors_count; s++) {
compute_postnum_recursive(postnum, cur, cfg, block->successors[s]);
}
postnum[block_num] = (*cur)++;
}
/* }}} */
/* Computes dominator tree using algorithm from "A Simple, Fast Dominance Algorithm" by
* Cooper, Harvey and Kennedy. */
ZEND_API int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */
{
zend_basic_block *blocks = cfg->blocks;
int blocks_count = cfg->blocks_count;
int j, k, changed;
ALLOCA_FLAG(use_heap)
int *postnum = do_alloca(sizeof(int) * cfg->blocks_count, use_heap);
memset(postnum, -1, sizeof(int) * cfg->blocks_count);
j = 0;
compute_postnum_recursive(postnum, &j, cfg, 0);
/* FIXME: move declarations */
blocks[0].idom = 0;
do {
changed = 0;
/* Iterating in RPO here would converge faster */
for (j = 1; j < blocks_count; j++) {
int idom = -1;
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
for (k = 0; k < blocks[j].predecessors_count; k++) {
int pred = cfg->predecessors[blocks[j].predecessor_offset + k];
if (idom < 0) {
if (blocks[pred].idom >= 0)
idom = pred;
continue;
}
if (blocks[pred].idom >= 0) {
while (idom != pred) {
while (postnum[pred] < postnum[idom]) pred = blocks[pred].idom;
while (postnum[idom] < postnum[pred]) idom = blocks[idom].idom;
}
}
}
if (idom >= 0 && blocks[j].idom != idom) {
blocks[j].idom = idom;
changed = 1;
}
}
} while (changed);
blocks[0].idom = -1;
for (j = 1; j < blocks_count; j++) {
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
if (blocks[j].idom >= 0) {
/* Sort by block number to traverse children in pre-order */
if (blocks[blocks[j].idom].children < 0 ||
j < blocks[blocks[j].idom].children) {
blocks[j].next_child = blocks[blocks[j].idom].children;
blocks[blocks[j].idom].children = j;
} else {
int k = blocks[blocks[j].idom].children;
while (blocks[k].next_child >=0 && j > blocks[k].next_child) {
k = blocks[k].next_child;
}
blocks[j].next_child = blocks[k].next_child;
blocks[k].next_child = j;
}
}
}
for (j = 0; j < blocks_count; j++) {
int idom = blocks[j].idom, level = 0;
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
while (idom >= 0) {
level++;
if (blocks[idom].level >= 0) {
level += blocks[idom].level;
break;
} else {
idom = blocks[idom].idom;
}
}
blocks[j].level = level;
}
free_alloca(postnum, use_heap);
return SUCCESS;
}
/* }}} */
static int dominates(zend_basic_block *blocks, int a, int b) /* {{{ */
{
while (blocks[b].level > blocks[a].level) {
b = blocks[b].idom;
}
return a == b;
}
/* }}} */
typedef struct {
int id;
int level;
} block_info;
static int compare_block_level(const block_info *a, const block_info *b) {
return b->level - a->level;
}
static void swap_blocks(block_info *a, block_info *b) {
block_info tmp = *a;
*a = *b;
*b = tmp;
}
ZEND_API int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */
{
int i, j, k, n;
int time;
zend_basic_block *blocks = cfg->blocks;
int *entry_times, *exit_times;
zend_worklist work;
int flag = ZEND_FUNC_NO_LOOPS;
block_info *sorted_blocks;
ALLOCA_FLAG(list_use_heap)
ALLOCA_FLAG(tree_use_heap)
ALLOCA_FLAG(sorted_blocks_use_heap)
ZEND_WORKLIST_ALLOCA(&work, cfg->blocks_count, list_use_heap);
/* We don't materialize the DJ spanning tree explicitly, as we are only interested in ancestor
* queries. These are implemented by checking entry/exit times of the DFS search. */
entry_times = do_alloca(2 * sizeof(int) * cfg->blocks_count, tree_use_heap);
exit_times = entry_times + cfg->blocks_count;
memset(entry_times, -1, 2 * sizeof(int) * cfg->blocks_count);
zend_worklist_push(&work, 0);
time = 0;
while (zend_worklist_len(&work)) {
next:
i = zend_worklist_peek(&work);
if (entry_times[i] == -1) {
entry_times[i] = time++;
}
/* Visit blocks immediately dominated by i. */
for (j = blocks[i].children; j >= 0; j = blocks[j].next_child) {
if (zend_worklist_push(&work, j)) {
goto next;
}
}
/* Visit join edges. */
for (j = 0; j < blocks[i].successors_count; j++) {
int succ = blocks[i].successors[j];
if (blocks[succ].idom == i) {
continue;
} else if (zend_worklist_push(&work, succ)) {
goto next;
}
}
exit_times[i] = time++;
zend_worklist_pop(&work);
}
/* Sort blocks by decreasing level, which is the order in which we want to process them */
sorted_blocks = do_alloca(sizeof(block_info) * cfg->blocks_count, sorted_blocks_use_heap);
for (i = 0; i < cfg->blocks_count; i++) {
sorted_blocks[i].id = i;
sorted_blocks[i].level = blocks[i].level;
}
zend_sort(sorted_blocks, cfg->blocks_count, sizeof(block_info),
(compare_func_t) compare_block_level, (swap_func_t) swap_blocks);
/* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ
Graphs". */
for (n = 0; n < cfg->blocks_count; n++) {
i = sorted_blocks[n].id;
zend_bitset_clear(work.visited, zend_bitset_len(cfg->blocks_count));
for (j = 0; j < blocks[i].predecessors_count; j++) {
int pred = cfg->predecessors[blocks[i].predecessor_offset + j];
/* A join edge is one for which the predecessor does not
immediately dominate the successor. */
if (blocks[i].idom == pred) {
continue;
}
/* In a loop back-edge (back-join edge), the successor dominates
the predecessor. */
if (dominates(blocks, i, pred)) {
blocks[i].flags |= ZEND_BB_LOOP_HEADER;
flag &= ~ZEND_FUNC_NO_LOOPS;
zend_worklist_push(&work, pred);
} else {
/* Otherwise it's a cross-join edge. See if it's a branch
to an ancestor on the DJ spanning tree. */
if (entry_times[pred] > entry_times[i] && exit_times[pred] < exit_times[i]) {
blocks[i].flags |= ZEND_BB_IRREDUCIBLE_LOOP;
flag |= ZEND_FUNC_IRREDUCIBLE;
flag &= ~ZEND_FUNC_NO_LOOPS;
}
}
}
while (zend_worklist_len(&work)) {
j = zend_worklist_pop(&work);
while (blocks[j].loop_header >= 0) {
j = blocks[j].loop_header;
}
if (j != i) {
blocks[j].loop_header = i;
for (k = 0; k < blocks[j].predecessors_count; k++) {
zend_worklist_push(&work, cfg->predecessors[blocks[j].predecessor_offset + k]);
}
}
}
}
free_alloca(sorted_blocks, sorted_blocks_use_heap);
free_alloca(entry_times, tree_use_heap);
ZEND_WORKLIST_FREE_ALLOCA(&work, list_use_heap);
cfg->flags |= flag;
return SUCCESS;
}
/* }}} */
-127
View File
@@ -1,127 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_CFG_H
#define ZEND_CFG_H
/* zend_basic_block.flags */
#define ZEND_BB_START (1<<0) /* first block */
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
#define ZEND_BB_TARGET (1<<2) /* jump target */
#define ZEND_BB_EXIT (1<<3) /* without successors */
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
#define ZEND_BB_TRY (1<<5) /* start of try block */
#define ZEND_BB_CATCH (1<<6) /* start of catch block */
#define ZEND_BB_FINALLY (1<<7) /* start of finally block */
#define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */
#define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */
#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */
#define ZEND_BB_LOOP_HEADER (1<<16)
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)
#define ZEND_BB_REACHABLE (1U<<31)
#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_UNREACHABLE_FREE)
typedef struct _zend_basic_block {
int *successors; /* successor block indices */
uint32_t flags;
uint32_t start; /* first opcode number */
uint32_t len; /* number of opcodes */
int successors_count; /* number of successors */
int predecessors_count; /* number of predecessors */
int predecessor_offset; /* offset of 1-st predecessor */
int idom; /* immediate dominator block */
int loop_header; /* closest loop header, or -1 */
int level; /* steps away from the entry in the dom. tree */
int children; /* list of dominated blocks */
int next_child; /* next dominated block */
int successors_storage[2]; /* up to 2 successor blocks */
} zend_basic_block;
/*
+------------+---+---+---+---+---+
| |OP1|OP2|EXT| 0 | 1 |
+------------+---+---+---+---+---+
|JMP |ADR| | |OP1| - |
|JMPZ | |ADR| |OP2|FOL|
|JMPNZ | |ADR| |OP2|FOL|
|JMPZNZ | |ADR|ADR|OP2|EXT|
|JMPZ_EX | |ADR| |OP2|FOL|
|JMPNZ_EX | |ADR| |OP2|FOL|
|JMP_SET | |ADR| |OP2|FOL|
|COALESCE | |ADR| |OP2|FOL|
|ASSERT_CHK | |ADR| |OP2|FOL|
|NEW | |ADR| |OP2|FOL|
|DCL_ANON* |ADR| | |OP1|FOL|
|FE_RESET_* | |ADR| |OP2|FOL|
|FE_FETCH_* | | |ADR|EXT|FOL|
|CATCH | | |ADR|EXT|FOL|
|FAST_CALL |ADR| | |OP1|FOL|
|FAST_RET | | | | - | - |
|RETURN* | | | | - | - |
|EXIT | | | | - | - |
|THROW | | | | - | - |
|* | | | |FOL| - |
+------------+---+---+---+---+---+
*/
typedef struct _zend_cfg {
int blocks_count; /* number of basic blocks */
int edges_count; /* number of edges */
zend_basic_block *blocks; /* array of basic blocks */
int *predecessors;
uint32_t *map;
uint32_t flags;
} zend_cfg;
/* Build Flags */
#define ZEND_CFG_STACKLESS (1<<30)
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
#define ZEND_SSA_RC_INFERENCE (1<<27)
#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)
#define ZEND_CFG_RECV_ENTRY (1<<24)
#define ZEND_CALL_TREE (1<<23)
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
#define CRT_CONSTANT_EX(op_array, opline, node) \
(((op_array)->fn_flags & ZEND_ACC_DONE_PASS_TWO) ? \
RT_CONSTANT(opline, (node)) \
: \
CT_CONSTANT_EX(op_array, (node).constant) \
)
#define CRT_CONSTANT(node) \
CRT_CONSTANT_EX(op_array, opline, node)
#define RETURN_VALUE_USED(opline) \
((opline)->result_type != IS_UNUSED)
BEGIN_EXTERN_C()
ZEND_API int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg);
ZEND_API int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg);
ZEND_API int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg);
ZEND_API int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg);
END_EXTERN_C()
#endif /* ZEND_CFG_H */
-332
View File
@@ -1,332 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#include "zend_compile.h"
#include "zend_dfg.h"
static zend_always_inline void _zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
{
uint32_t var_num;
const zend_op *next;
if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(opline->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
}
if (((opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
&& opline->opcode != ZEND_FE_FETCH_R
&& opline->opcode != ZEND_FE_FETCH_RW)
|| (opline->op2_type == IS_CV)) {
var_num = EX_VAR_TO_NUM(opline->op2.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
}
if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
&& opline->result_type == IS_CV
&& opline->opcode != ZEND_RECV) {
var_num = EX_VAR_TO_NUM(opline->result.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
}
switch (opline->opcode) {
case ZEND_ASSIGN:
if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
}
if (opline->op1_type == IS_CV) {
add_op1_def:
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op1.var));
}
break;
case ZEND_ASSIGN_REF:
if (opline->op2_type == IS_CV) {
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
}
if (opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
if (build_flags & ZEND_SSA_RC_INFERENCE && next->op1_type == IS_CV) {
zend_bitset_incl(def, var_num);
}
}
if (opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_ASSIGN_OBJ_REF:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
if (next->op1_type == IS_CV) {
zend_bitset_incl(def, var_num);
}
}
if (opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_ASSIGN_STATIC_PROP:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
zend_bitset_incl(def, var_num);
}
}
break;
case ZEND_ASSIGN_STATIC_PROP_REF:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
if (next->op1_type == IS_CV) {
zend_bitset_incl(def, var_num);
}
}
break;
case ZEND_ASSIGN_STATIC_PROP_OP:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
}
break;
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:
next = opline + 1;
if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
var_num = EX_VAR_TO_NUM(next->op1.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
}
if (opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_ASSIGN_OP:
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
case ZEND_POST_INC:
case ZEND_POST_DEC:
case ZEND_BIND_GLOBAL:
case ZEND_BIND_STATIC:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
case ZEND_SEND_REF:
case ZEND_SEND_UNPACK:
case ZEND_FE_RESET_RW:
case ZEND_MAKE_REF:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
case ZEND_UNSET_DIM:
case ZEND_UNSET_OBJ:
case ZEND_FETCH_DIM_W:
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
case ZEND_FETCH_LIST_W:
if (opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_SEND_VAR:
case ZEND_CAST:
case ZEND_QM_ASSIGN:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_FE_RESET_R:
if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_ADD_ARRAY_UNPACK:
var_num = EX_VAR_TO_NUM(opline->result.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
break;
case ZEND_ADD_ARRAY_ELEMENT:
var_num = EX_VAR_TO_NUM(opline->result.var);
if (!zend_bitset_in(def, var_num)) {
zend_bitset_incl(use, var_num);
}
ZEND_FALLTHROUGH;
case ZEND_INIT_ARRAY:
if (((build_flags & ZEND_SSA_RC_INFERENCE)
|| (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
&& opline->op1_type == IS_CV) {
goto add_op1_def;
}
break;
case ZEND_YIELD:
if (opline->op1_type == IS_CV
&& ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
|| (build_flags & ZEND_SSA_RC_INFERENCE))) {
goto add_op1_def;
}
break;
case ZEND_UNSET_CV:
goto add_op1_def;
case ZEND_VERIFY_RETURN_TYPE:
if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
goto add_op1_def;
}
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
#if 0
/* This special case was handled above the switch */
if (opline->op2_type != IS_CV) {
op2_use = -1; /* not used */
}
#endif
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
break;
case ZEND_BIND_LEXICAL:
if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
}
break;
default:
break;
}
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
zend_bitset_incl(def, EX_VAR_TO_NUM(opline->result.var));
}
}
/* }}} */
ZEND_API void zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
{
_zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
}
/* }}} */
int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags) /* {{{ */
{
int set_size;
zend_basic_block *blocks = cfg->blocks;
int blocks_count = cfg->blocks_count;
zend_bitset tmp, def, use, in, out;
int k;
int j;
set_size = dfg->size;
tmp = dfg->tmp;
def = dfg->def;
use = dfg->use;
in = dfg->in;
out = dfg->out;
/* Collect "def" and "use" sets */
for (j = 0; j < blocks_count; j++) {
zend_op *opline, *end;
zend_bitset b_use, b_def;
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
opline = op_array->opcodes + blocks[j].start;
end = opline + blocks[j].len;
b_use = DFG_BITSET(use, set_size, j);
b_def = DFG_BITSET(def, set_size, j);
for (; opline < end; opline++) {
if (opline->opcode != ZEND_OP_DATA) {
_zend_dfg_add_use_def_op(op_array, opline, build_flags, b_use, b_def);
}
}
}
/* Calculate "in" and "out" sets */
{
uint32_t worklist_len = zend_bitset_len(blocks_count);
zend_bitset worklist;
ALLOCA_FLAG(use_heap);
worklist = ZEND_BITSET_ALLOCA(worklist_len, use_heap);
memset(worklist, 0, worklist_len * ZEND_BITSET_ELM_SIZE);
for (j = 0; j < blocks_count; j++) {
zend_bitset_incl(worklist, j);
}
while (!zend_bitset_empty(worklist, worklist_len)) {
/* We use the last block on the worklist, because predecessors tend to be located
* before the succeeding block, so this converges faster. */
j = zend_bitset_last(worklist, worklist_len);
zend_bitset_excl(worklist, j);
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
if (blocks[j].successors_count != 0) {
zend_bitset_copy(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[0]), set_size);
for (k = 1; k < blocks[j].successors_count; k++) {
zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[k]), set_size);
}
} else {
zend_bitset_clear(DFG_BITSET(out, set_size, j), set_size);
}
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);
if (!zend_bitset_equal(DFG_BITSET(in, set_size, j), tmp, set_size)) {
zend_bitset_copy(DFG_BITSET(in, set_size, j), tmp, set_size);
/* Add predecessors of changed block to worklist */
{
int *predecessors = &cfg->predecessors[blocks[j].predecessor_offset];
for (k = 0; k < blocks[j].predecessors_count; k++) {
zend_bitset_incl(worklist, predecessors[k]);
}
}
}
}
free_alloca(worklist, use_heap);
}
return SUCCESS;
}
/* }}} */
-51
View File
@@ -1,51 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_DFG_H
#define ZEND_DFG_H
#include "zend_bitset.h"
#include "zend_cfg.h"
typedef struct _zend_dfg {
int vars;
uint32_t size;
zend_bitset tmp;
zend_bitset def;
zend_bitset use;
zend_bitset in;
zend_bitset out;
} zend_dfg;
#define DFG_BITSET(set, set_size, block_num) \
((set) + ((block_num) * (set_size)))
#define DFG_SET(set, set_size, block_num, var_num) \
zend_bitset_incl(DFG_BITSET(set, set_size, block_num), (var_num))
#define DFG_ISSET(set, set_size, block_num, var_num) \
zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num))
BEGIN_EXTERN_C()
int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags);
ZEND_API void zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def);
END_EXTERN_C()
#endif /* ZEND_DFG_H */
File diff suppressed because it is too large. Load diff
-48
View File
@@ -1,48 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Bytecode Visualisation |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_DUMP_H
#define ZEND_DUMP_H
#include "zend_ssa.h"
#include "zend_dfg.h"
#define ZEND_DUMP_HIDE_UNREACHABLE (1<<0)
#define ZEND_DUMP_RC_INFERENCE (1<<1)
#define ZEND_DUMP_CFG (1<<2)
#define ZEND_DUMP_SSA (1<<3)
#define ZEND_DUMP_LIVE_RANGES (1<<4)
BEGIN_EXTERN_C()
ZEND_API void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data);
ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op);
void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg);
void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg);
void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa);
void zend_dump_variables(const zend_op_array *op_array);
void zend_dump_ssa_variables(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t dump_flags);
ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, zend_uchar var_type, int var_num, uint32_t dump_flags);
ZEND_API void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num);
void zend_dump_op_array_name(const zend_op_array *op_array);
void zend_dump_const(const zval *zv);
void zend_dump_ht(HashTable *ht);
END_EXTERN_C()
#endif /* ZEND_DUMP_H */
-924
View File
@@ -1,924 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
| Xinchen Hui <laruence@php.net> |
+----------------------------------------------------------------------+
*/
#include "zend_compile.h"
#include "zend_extensions.h"
#include "zend_ssa.h"
#include "zend_optimizer_internal.h"
#include "zend_inference.h"
#include "zend_call_graph.h"
#include "zend_func_info.h"
#include "zend_inference.h"
#ifdef _WIN32
#include "win32/ioutil.h"
#endif
typedef uint32_t (*info_func_t)(const zend_call_info *call_info, const zend_ssa *ssa);
typedef struct _func_info_t {
const char *name;
int name_len;
uint32_t info;
info_func_t info_func;
} func_info_t;
#define F0(name, info) \
{name, sizeof(name)-1, (info), NULL}
#define F1(name, info) \
{name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
#define FN(name, info) \
{name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
#define FC(name, callback) \
{name, sizeof(name)-1, 0, callback}
static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa *ssa)
{
if (!call_info->send_unpack
&& (call_info->num_args == 2 || call_info->num_args == 3)
&& ssa
&& !(ssa->cfg.flags & ZEND_SSA_TSSA)) {
zend_op_array *op_array = call_info->caller_op_array;
uint32_t t1 = _ssa_op1_info(op_array, ssa, call_info->arg_info[0].opline,
&ssa->ops[call_info->arg_info[0].opline - op_array->opcodes]);
uint32_t t2 = _ssa_op1_info(op_array, ssa, call_info->arg_info[1].opline,
&ssa->ops[call_info->arg_info[1].opline - op_array->opcodes]);
uint32_t t3 = 0;
uint32_t tmp = MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED;
if (call_info->num_args == 3) {
t3 = _ssa_op1_info(op_array, ssa, call_info->arg_info[2].opline,
&ssa->ops[call_info->arg_info[2].opline - op_array->opcodes]);
}
if ((t1 & MAY_BE_STRING) && (t2 & MAY_BE_STRING)) {
tmp |= MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
}
if ((t1 & (MAY_BE_DOUBLE|MAY_BE_STRING))
|| (t2 & (MAY_BE_DOUBLE|MAY_BE_STRING))
|| (t3 & (MAY_BE_DOUBLE|MAY_BE_STRING))) {
tmp |= MAY_BE_ARRAY_OF_DOUBLE;
}
if ((t1 & (MAY_BE_ANY-(MAY_BE_STRING|MAY_BE_DOUBLE))) && (t2 & (MAY_BE_ANY-(MAY_BE_STRING|MAY_BE_DOUBLE)))) {
if ((t3 & MAY_BE_ANY) != MAY_BE_DOUBLE) {
tmp |= MAY_BE_ARRAY_OF_LONG;
}
}
return tmp;
} else {
/* May throw */
return MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
}
}
static const func_info_t func_infos[] = {
/* zend */
F1("zend_version", MAY_BE_STRING),
FN("func_get_args", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("get_class_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
F1("get_class_methods", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
FN("set_error_handler", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
F0("restore_error_handler", MAY_BE_TRUE),
F0("restore_exception_handler", MAY_BE_TRUE),
F1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("get_defined_functions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
F1("get_resource_type", MAY_BE_STRING),
F1("get_defined_constants", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_RESOURCE | MAY_BE_ARRAY_OF_ARRAY),
F1("debug_backtrace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("get_loaded_extensions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("get_extension_funcs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
/* ext/standard */
FN("constant", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("bin2hex", MAY_BE_STRING),
F1("hex2bin", MAY_BE_FALSE | MAY_BE_STRING),
#if HAVE_NANOSLEEP
F1("time_nanosleep", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#if HAVE_STRPTIME
F1("strptime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
F1("wordwrap", MAY_BE_STRING),
F1("htmlspecialchars", MAY_BE_STRING),
F1("htmlentities", MAY_BE_STRING),
F1("get_html_translation_table", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("sha1", MAY_BE_STRING),
F1("sha1_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("md5", MAY_BE_STRING),
F1("md5_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("iptcparse", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("iptcembed", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("getimagesize", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("getimagesizefromstring", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("image_type_to_mime_type", MAY_BE_STRING),
F1("image_type_to_extension", MAY_BE_FALSE | MAY_BE_STRING),
F0("phpinfo", MAY_BE_TRUE),
F1("phpversion", MAY_BE_FALSE | MAY_BE_STRING),
F0("phpcredits", MAY_BE_TRUE),
F1("php_sapi_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("php_uname", MAY_BE_STRING),
F1("php_ini_scanned_files", MAY_BE_FALSE | MAY_BE_STRING),
F1("php_ini_loaded_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("strtok", MAY_BE_FALSE | MAY_BE_STRING),
F1("strrev", MAY_BE_STRING),
F1("hebrev", MAY_BE_STRING),
F1("basename", MAY_BE_STRING),
F1("dirname", MAY_BE_STRING),
F1("pathinfo", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("stripslashes", MAY_BE_STRING),
F1("stripcslashes", MAY_BE_STRING),
F1("strstr", MAY_BE_FALSE | MAY_BE_STRING),
F1("stristr", MAY_BE_FALSE | MAY_BE_STRING),
F1("strrchr", MAY_BE_FALSE | MAY_BE_STRING),
F1("str_shuffle", MAY_BE_STRING),
F1("str_word_count", MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("str_split", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("strpbrk", MAY_BE_FALSE | MAY_BE_STRING),
FN("substr_replace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
F1("quotemeta", MAY_BE_STRING),
F1("ucwords", MAY_BE_STRING),
F1("addcslashes", MAY_BE_STRING),
FN("str_replace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
FN("str_ireplace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
F1("str_repeat", MAY_BE_STRING),
F1("count_chars", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("chunk_split", MAY_BE_STRING),
F1("strip_tags", MAY_BE_STRING),
F1("explode", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("localeconv", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if HAVE_NL_LANGINFO
F1("nl_langinfo", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F1("soundex", MAY_BE_STRING),
F1("chr", MAY_BE_STRING),
F1("str_getcsv", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("strchr", MAY_BE_FALSE | MAY_BE_STRING),
F1("sprintf", MAY_BE_STRING),
F1("vsprintf", MAY_BE_STRING),
F1("sscanf", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("fscanf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("parse_url", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_LONG),
F1("urlencode", MAY_BE_STRING),
F1("urldecode", MAY_BE_STRING),
F1("rawurlencode", MAY_BE_STRING),
F1("rawurldecode", MAY_BE_STRING),
F1("http_build_query", MAY_BE_STRING),
#if defined(HAVE_SYMLINK) || defined(PHP_WIN32)
F1("readlink", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F1("exec", MAY_BE_FALSE | MAY_BE_STRING),
F1("system", MAY_BE_FALSE | MAY_BE_STRING),
F1("escapeshellcmd", MAY_BE_STRING),
F1("escapeshellarg", MAY_BE_STRING),
F0("passthru", MAY_BE_NULL | MAY_BE_FALSE),
F1("shell_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
F1("proc_open", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("proc_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
F1("random_bytes", MAY_BE_STRING),
#if HAVE_GETSERVBYPORT
F1("getservbyport", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if HAVE_GETPROTOBYNUMBER
F1("getprotobynumber", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F1("base64_decode", MAY_BE_FALSE | MAY_BE_STRING),
F1("base64_encode", MAY_BE_STRING),
F1("password_hash", MAY_BE_STRING),
F1("password_get_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("convert_uuencode", MAY_BE_STRING),
F1("convert_uudecode", MAY_BE_FALSE | MAY_BE_STRING),
F1("pow", MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_OBJECT),
F1("decbin", MAY_BE_STRING),
F1("decoct", MAY_BE_STRING),
F1("dechex", MAY_BE_STRING),
F1("base_convert", MAY_BE_STRING),
F1("number_format", MAY_BE_STRING),
#ifdef HAVE_INET_NTOP
F1("inet_ntop", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#ifdef HAVE_INET_PTON
F1("inet_pton", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F1("long2ip", MAY_BE_FALSE | MAY_BE_STRING),
F1("getenv", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_PUTENV
#endif
F1("getopt", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#ifdef HAVE_GETLOADAVG
F1("sys_getloadavg", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
#endif
#ifdef HAVE_GETTIMEOFDAY
F1("microtime", MAY_BE_DOUBLE | MAY_BE_STRING),
F1("gettimeofday", MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETRUSAGE
F1("getrusage", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETTIMEOFDAY
F1("uniqid", MAY_BE_STRING),
#endif
F1("quoted_printable_decode", MAY_BE_STRING),
F1("quoted_printable_encode", MAY_BE_STRING),
F1("get_current_user", MAY_BE_STRING),
F1("get_cfg_var", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("error_get_last", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("serialize", MAY_BE_STRING),
F1("var_export", MAY_BE_NULL | MAY_BE_STRING),
F1("print_r", MAY_BE_TRUE | MAY_BE_STRING),
F0("register_shutdown_function", MAY_BE_NULL | MAY_BE_FALSE),
F1("highlight_file", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("show_source", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("highlight_string", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("php_strip_whitespace", MAY_BE_STRING),
F1("ini_get_all", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("ini_alter", MAY_BE_FALSE | MAY_BE_STRING),
F1("get_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F1("set_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F1("headers_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("parse_ini_file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("parse_ini_string", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if ZEND_DEBUG
F1("config_get_hash", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#endif
F1("gethostbyaddr", MAY_BE_FALSE | MAY_BE_STRING),
F1("gethostbyname", MAY_BE_STRING),
F1("gethostbynamel", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GETHOSTNAME
F1("gethostname", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if defined(PHP_WIN32) || HAVE_DNS_SEARCH_FUNC
# if defined(PHP_WIN32) || HAVE_FULL_DNS_FUNCS
F1("dns_get_record", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
# endif
#endif
F1("popen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("fgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("fgets", MAY_BE_FALSE | MAY_BE_STRING),
F1("fread", MAY_BE_FALSE | MAY_BE_STRING),
F1("fopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("fstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
F1("tempnam", MAY_BE_FALSE | MAY_BE_STRING),
F1("tmpfile", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("file_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
F1("stream_context_create", MAY_BE_RESOURCE),
F1("stream_context_get_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
FN("stream_context_get_options", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
FN("stream_context_get_default", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_context_set_default", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_filter_prepend", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_filter_append", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_client", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_server", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_accept", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_get_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("stream_socket_recvfrom", MAY_BE_FALSE | MAY_BE_STRING),
#if HAVE_SOCKETPAIR
F1("stream_socket_pair", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_RESOURCE),
#endif
F1("stream_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
F1("fgetcsv", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("get_meta_tags", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("stream_get_meta_data", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("stream_get_line", MAY_BE_FALSE | MAY_BE_STRING),
F1("stream_get_wrappers", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("stream_get_transports", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("stream_resolve_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F1("get_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("socket_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("realpath", MAY_BE_FALSE | MAY_BE_STRING),
F1("fsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("pfsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("pack", MAY_BE_STRING),
F1("unpack", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("get_browser", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("crypt", MAY_BE_STRING),
FN("opendir", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("getcwd", MAY_BE_FALSE | MAY_BE_STRING),
F1("readdir", MAY_BE_FALSE | MAY_BE_STRING),
F1("dir", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("scandir", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GLOB
F1("glob", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
F1("filetype", MAY_BE_FALSE | MAY_BE_STRING),
F1("stat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("lstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("realpath_cache_get", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
#ifdef HAVE_SYSLOG_H
F0("syslog", MAY_BE_TRUE),
F0("closelog", MAY_BE_TRUE),
#endif
F1("metaphone", MAY_BE_STRING),
F1("ob_get_flush", MAY_BE_FALSE | MAY_BE_STRING),
F1("ob_get_clean", MAY_BE_FALSE | MAY_BE_STRING),
F1("ob_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("ob_list_handlers", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F0("array_walk", MAY_BE_TRUE),
F0("array_walk_recursive", MAY_BE_TRUE),
F0("arsort", MAY_BE_TRUE),
F0("asort", MAY_BE_TRUE),
F0("krsort", MAY_BE_TRUE),
F0("ksort", MAY_BE_TRUE),
F0("shuffle", MAY_BE_TRUE),
F0("sort", MAY_BE_TRUE),
F0("usort", MAY_BE_TRUE),
F0("uasort", MAY_BE_TRUE),
F0("uksort", MAY_BE_TRUE),
F1("compact", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_fill", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("array_fill_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FC("range", zend_range_info),
F1("array_splice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_slice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_replace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_replace_recursive", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FN("array_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
FN("array_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_count_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
F1("array_column", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_reverse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_flip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("array_change_key_case", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FN("array_rand", MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("array_intersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_intersect_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_intersect_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_uintersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_intersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_uintersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_intersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_uintersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_diff_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_diff_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_udiff", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_diff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_udiff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_diff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_udiff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_filter", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_chunk", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_combine", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("str_rot13", MAY_BE_STRING),
F1("stream_get_filters", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("stream_bucket_make_writeable", MAY_BE_NULL | MAY_BE_OBJECT),
F1("stream_bucket_new", MAY_BE_OBJECT),
F1("sys_get_temp_dir", MAY_BE_STRING),
/* ext/date */
F1("date", MAY_BE_STRING),
F1("gmdate", MAY_BE_STRING),
F1("strftime", MAY_BE_FALSE | MAY_BE_STRING),
F1("gmstrftime", MAY_BE_FALSE | MAY_BE_STRING),
F1("localtime", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
F1("getdate", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("date_create", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_parse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("date_parse_from_format", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("date_get_last_errors", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("date_format", MAY_BE_STRING),
F1("date_timezone_get", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_diff", MAY_BE_OBJECT),
F1("timezone_open", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("timezone_name_get", MAY_BE_STRING),
F1("timezone_name_from_abbr", MAY_BE_FALSE | MAY_BE_STRING),
F1("timezone_transitions_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("timezone_location_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING),
F1("timezone_identifiers_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("timezone_abbreviations_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("timezone_version_get", MAY_BE_STRING),
F1("date_interval_create_from_date_string", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_interval_format", MAY_BE_STRING),
F1("date_default_timezone_get", MAY_BE_STRING),
F1("date_sunrise", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
F1("date_sunset", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
F1("date_sun_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG),
/* ext/preg */
FN("preg_replace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
FN("preg_replace_callback", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
F1("preg_filter", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
F1("preg_split", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("preg_grep", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
/* ext/mysqli */
F1("mysqli_connect", MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_close", MAY_BE_TRUE),
F1("mysqli_connect_error", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_get_client_stats", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("mysqli_error_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("mysqli_get_links_stats", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
F1("mysqli_query", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT),
F1("mysqli_get_charset", MAY_BE_NULL | MAY_BE_OBJECT),
F1("mysqli_fetch_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_all", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_object", MAY_BE_NULL | MAY_BE_OBJECT),
F1("mysqli_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_character_set_name", MAY_BE_STRING),
F0("mysqli_debug", MAY_BE_TRUE),
F1("mysqli_error", MAY_BE_STRING),
F1("mysqli_reap_async_query", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT),
F1("mysqli_stmt_get_result", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_get_warnings", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_stmt_error_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("mysqli_stmt_get_warnings", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_fetch_field", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_fetch_fields", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_OBJECT),
F1("mysqli_fetch_field_direct", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_fetch_lengths", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("mysqli_fetch_row", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_get_client_info", MAY_BE_STRING),
F1("mysqli_get_host_info", MAY_BE_STRING),
F1("mysqli_get_server_info", MAY_BE_STRING),
F1("mysqli_info", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_init", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_insert_id", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_num_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_prepare", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_real_escape_string", MAY_BE_STRING),
F1("mysqli_stmt_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_stmt_insert_id", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_stmt_num_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_sqlstate", MAY_BE_STRING),
F0("mysqli_ssl_set", MAY_BE_TRUE),
F1("mysqli_stat", MAY_BE_FALSE | MAY_BE_STRING),
F1("mysqli_stmt_error", MAY_BE_STRING),
F1("mysqli_stmt_init", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_stmt_result_metadata", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_stmt_sqlstate", MAY_BE_STRING),
F1("mysqli_store_result", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_use_result", MAY_BE_FALSE | MAY_BE_OBJECT),
/* ext/curl */
F1("curl_init", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("curl_copy_handle", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("curl_version", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("curl_error", MAY_BE_STRING),
F1("curl_strerror", MAY_BE_NULL | MAY_BE_STRING),
F1("curl_multi_strerror", MAY_BE_NULL | MAY_BE_STRING),
F1("curl_escape", MAY_BE_FALSE | MAY_BE_STRING),
F1("curl_unescape", MAY_BE_FALSE | MAY_BE_STRING),
F1("curl_multi_init", MAY_BE_OBJECT),
F1("curl_multi_info_read", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_OBJECT),
F1("curl_share_init", MAY_BE_OBJECT),
F1("curl_file_create", MAY_BE_OBJECT),
/* ext/mbstring */
F1("mb_convert_case", MAY_BE_STRING),
F1("mb_strtoupper", MAY_BE_STRING),
F1("mb_strtolower", MAY_BE_STRING),
F1("mb_language", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("mb_internal_encoding", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("mb_http_input", MAY_BE_FALSE | MAY_BE_STRING| MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_http_output", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("mb_detect_order", MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_substitute_character", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_STRING),
F1("mb_output_handler", MAY_BE_STRING),
F1("mb_preferred_mime_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_strstr", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_strrchr", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_stristr", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_strrichr", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_substr", MAY_BE_STRING),
F1("mb_strcut", MAY_BE_STRING),
F1("mb_strimwidth", MAY_BE_STRING),
F1("mb_convert_encoding", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mb_detect_encoding", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_list_encodings", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_encoding_aliases", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_convert_kana", MAY_BE_STRING),
F1("mb_encode_mimeheader", MAY_BE_STRING),
F1("mb_decode_mimeheader", MAY_BE_STRING),
F1("mb_convert_variables", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_encode_numericentity", MAY_BE_STRING),
F1("mb_decode_numericentity", MAY_BE_STRING),
F1("mb_get_info", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("mb_regex_encoding", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("mb_regex_set_options", MAY_BE_STRING),
F1("mb_ereg_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_eregi_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_ereg_replace_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_split", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_ereg_search_pos", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("mb_ereg_search_regs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_STRING),
F1("mb_ereg_search_getregs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_STRING),
/* ext/iconv */
F1("iconv", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_get_encoding", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("iconv_substr", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_mime_encode", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_mime_decode", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_mime_decode_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
/* ext/json */
F1("json_encode", MAY_BE_FALSE | MAY_BE_STRING),
F1("json_decode", MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("json_last_error_msg", MAY_BE_STRING),
/* ext/xml */
F1("xml_error_string", MAY_BE_NULL | MAY_BE_STRING),
F1("xml_parser_get_option", MAY_BE_LONG | MAY_BE_STRING),
F1("utf8_encode", MAY_BE_STRING),
F1("utf8_decode", MAY_BE_STRING),
/* ext/zlib */
F1("gzgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzgets", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzread", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzopen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("gzfile", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("gzcompress", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzuncompress", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzdeflate", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzinflate", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzencode", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzdecode", MAY_BE_FALSE | MAY_BE_STRING),
F1("zlib_encode", MAY_BE_FALSE | MAY_BE_STRING),
F1("zlib_decode", MAY_BE_FALSE | MAY_BE_STRING),
F1("zlib_get_coding_type", MAY_BE_FALSE | MAY_BE_STRING),
F1("ob_gzhandler", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/hash */
F1("hash", MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hmac", MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hmac_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("hash_hmac_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hkdf", MAY_BE_STRING),
F1("hash_init", MAY_BE_OBJECT),
F1("hash_final", MAY_BE_STRING),
F1("hash_copy", MAY_BE_OBJECT),
F1("hash_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("hash_pbkdf2", MAY_BE_STRING),
F1("mhash_keygen_s2k", MAY_BE_FALSE | MAY_BE_STRING),
F1("mhash_get_hash_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("mhash", MAY_BE_FALSE | MAY_BE_FALSE | MAY_BE_STRING),
/* ext/sodium */
F1("sodium_crypto_shorthash", MAY_BE_STRING),
F1("sodium_crypto_secretbox", MAY_BE_STRING),
F1("sodium_crypto_secretbox_open", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_generichash", MAY_BE_STRING),
F1("sodium_crypto_generichash_init", MAY_BE_STRING),
F0("sodium_crypto_generichash_update", MAY_BE_TRUE),
F1("sodium_crypto_generichash_final", MAY_BE_STRING),
F1("sodium_crypto_box_keypair", MAY_BE_STRING),
F1("sodium_crypto_box_seed_keypair", MAY_BE_STRING),
F1("sodium_crypto_box_secretkey", MAY_BE_STRING),
F1("sodium_crypto_box_publickey", MAY_BE_STRING),
F1("sodium_crypto_box", MAY_BE_STRING),
F1("sodium_crypto_box_open", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_box_seal", MAY_BE_STRING),
F1("sodium_crypto_box_seal_open", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_sign_keypair", MAY_BE_STRING),
F1("sodium_crypto_sign_seed_keypair", MAY_BE_STRING),
F1("sodium_crypto_sign_secretkey", MAY_BE_STRING),
F1("sodium_crypto_sign_publickey", MAY_BE_STRING),
F1("sodium_crypto_sign", MAY_BE_STRING),
F1("sodium_crypto_sign_open", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_sign_detached", MAY_BE_STRING),
F1("sodium_crypto_stream", MAY_BE_STRING),
F1("sodium_crypto_stream_xor", MAY_BE_STRING),
F1("sodium_crypto_pwhash", MAY_BE_STRING),
F1("sodium_crypto_pwhash_str", MAY_BE_STRING),
F1("sodium_crypto_aead_aes256gcm_encrypt", MAY_BE_STRING),
F1("sodium_crypto_aead_aes256gcm_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_bin2hex", MAY_BE_STRING),
F1("sodium_hex2bin", MAY_BE_STRING),
F1("sodium_crypto_scalarmult", MAY_BE_STRING),
F1("sodium_crypto_kx_seed_keypair", MAY_BE_STRING),
F1("sodium_crypto_kx_keypair", MAY_BE_STRING),
F1("sodium_crypto_kx_secretkey", MAY_BE_STRING),
F1("sodium_crypto_kx_publickey", MAY_BE_STRING),
F1("sodium_crypto_kx_client_session_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("sodium_crypto_kx_server_session_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("sodium_crypto_auth", MAY_BE_STRING),
F1("sodium_crypto_aead_aes256gcm_keygen", MAY_BE_STRING),
F1("sodium_crypto_auth_keygen", MAY_BE_STRING),
F1("sodium_crypto_generichash_keygen", MAY_BE_STRING),
F1("sodium_crypto_kdf_keygen", MAY_BE_STRING),
F1("sodium_crypto_secretbox_keygen", MAY_BE_STRING),
F1("sodium_crypto_shorthash_keygen", MAY_BE_STRING),
F1("sodium_crypto_stream_keygen", MAY_BE_STRING),
F1("sodium_crypto_kdf_derive_from_key", MAY_BE_STRING),
F1("sodium_pad", MAY_BE_STRING),
F1("sodium_unpad", MAY_BE_STRING),
F1("sodium_crypto_box_keypair_from_secretkey_and_publickey", MAY_BE_STRING),
F1("sodium_crypto_box_publickey_from_secretkey", MAY_BE_STRING),
F1("sodium_crypto_sign_keypair_from_secretkey_and_publickey", MAY_BE_STRING),
F1("sodium_crypto_sign_publickey_from_secretkey", MAY_BE_STRING),
F1("sodium_crypto_pwhash_scryptsalsa208sha256", MAY_BE_STRING),
F1("sodium_crypto_pwhash_scryptsalsa208sha256_str", MAY_BE_STRING),
F1("sodium_crypto_sign_ed25519_sk_to_curve25519", MAY_BE_STRING),
F1("sodium_crypto_sign_ed25519_pk_to_curve25519", MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_encrypt", MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_ietf_encrypt", MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_ietf_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_aead_xchacha20poly1305_ietf_encrypt", MAY_BE_STRING),
F1("sodium_crypto_aead_xchacha20poly1305_ietf_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_keygen", MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_ietf_keygen", MAY_BE_STRING),
F1("sodium_crypto_aead_xchacha20poly1305_ietf_keygen", MAY_BE_STRING),
/* ext/session */
F1("session_get_cookie_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("session_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("session_module_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("session_save_path", MAY_BE_FALSE | MAY_BE_STRING),
F1("session_create_id", MAY_BE_FALSE | MAY_BE_STRING),
F1("session_cache_limiter", MAY_BE_FALSE | MAY_BE_STRING),
F1("session_encode", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/pgsql */
F1("pg_dbname", MAY_BE_STRING),
F1("pg_options", MAY_BE_STRING),
F1("pg_port", MAY_BE_STRING),
F1("pg_tty", MAY_BE_STRING),
F1("pg_host", MAY_BE_STRING),
F1("pg_version", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_NULL),
F1("pg_parameter_status", MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_query", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_query_params", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_prepare", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_execute", MAY_BE_FALSE | MAY_BE_OBJECT),
FN("pg_last_notice", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY ),
F1("pg_field_name", MAY_BE_STRING),
F1("pg_field_type_oid", MAY_BE_LONG | MAY_BE_STRING),
F1("pg_fetch_result", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_fetch_row", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("pg_fetch_assoc", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("pg_fetch_array", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("pg_fetch_object", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_fetch_all", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("pg_fetch_all_columns", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("pg_last_oid", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
F1("pg_lo_create", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
F1("pg_lo_open", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_lo_read", MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_lo_import", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
F1("pg_copy_to", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("pg_escape_string", MAY_BE_STRING),
F1("pg_escape_bytea", MAY_BE_STRING),
F1("pg_unescape_bytea", MAY_BE_STRING),
F1("pg_escape_literal", MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_escape_identifier", MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_result_error", MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_result_error_field", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("pg_get_result", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_result_status", MAY_BE_LONG | MAY_BE_STRING),
F1("pg_get_notify", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("pg_socket", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("pg_meta_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("pg_convert", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("pg_insert", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT | MAY_BE_STRING),
F1("pg_update", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("pg_delete", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("pg_select", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
/* ext/bcmath */
F1("bcadd", MAY_BE_STRING),
F1("bcsub", MAY_BE_STRING),
F1("bcmul", MAY_BE_STRING),
F1("bcdiv", MAY_BE_STRING),
F1("bcmod", MAY_BE_STRING),
F1("bcpowmod", MAY_BE_STRING),
F1("bcpow", MAY_BE_STRING),
F1("bcsqrt", MAY_BE_STRING),
/* ext/exif */
F1("exif_tagname", MAY_BE_FALSE | MAY_BE_STRING),
F1("exif_read_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("exif_thumbnail", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/filter */
F1("filter_input_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("filter_var_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
F1("filter_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
/* ext/gettext */
F1("textdomain", MAY_BE_STRING),
F1("gettext", MAY_BE_STRING),
F1("_", MAY_BE_STRING),
F1("dgettext", MAY_BE_STRING),
F1("dcgettext", MAY_BE_STRING),
F1("bindtextdomain", MAY_BE_FALSE | MAY_BE_STRING),
#if HAVE_NGETTEXT
F1("ngettext", MAY_BE_STRING),
#endif
#if HAVE_DNGETTEXT
F1("dcngettext", MAY_BE_STRING),
#endif
#if HAVE_BIND_TEXTDOMAIN_CODESET
F1("bind_textdomain_codeset", MAY_BE_FALSE | MAY_BE_STRING),
#endif
/* ext/fileinfo */
F1("finfo_open", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("finfo_file", MAY_BE_FALSE | MAY_BE_STRING),
F1("finfo_buffer", MAY_BE_FALSE | MAY_BE_STRING),
F1("mime_content_type", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/gd */
F1("gd_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE),
F1("imagecreatetruecolor", MAY_BE_FALSE | MAY_BE_OBJECT),
#ifdef PHP_WIN32
F1("imagegrabwindow", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagegrabscreen", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
F1("imagerotate", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreate", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreatefromstring", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreatefromgif", MAY_BE_FALSE | MAY_BE_OBJECT),
#ifdef HAVE_GD_JPG
F1("imagecreatefromjpeg", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
#ifdef HAVE_GD_PNG
F1("imagecreatefrompng", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
#ifdef HAVE_GD_WEBP
F1("imagecreatefromwebp", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
F1("imagecreatefromxbm", MAY_BE_FALSE | MAY_BE_OBJECT),
#if defined(HAVE_GD_XPM)
F1("imagecreatefromxpm", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
F1("imagecreatefromwbmp", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreatefromgd", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreatefromgd2", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecreatefromgd2part", MAY_BE_FALSE | MAY_BE_OBJECT),
#if defined(HAVE_GD_BMP)
F1("imagecreatefrombmp", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
F0("imagecolorset", MAY_BE_NULL | MAY_BE_FALSE),
F1("imagecolorsforindex", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
F1("imagegetclip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imageftbbox", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagefttext", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagettfbbox", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagettftext", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagecrop", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagecropauto", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imagescale", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imageaffine", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("imageaffinematrixget", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
F1("imageaffinematrixconcat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
F1("imageresolution", MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
/* ext/spl */
F1("class_implements", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("class_parents", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("class_uses", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("iterator_to_array", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("spl_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("spl_object_hash", MAY_BE_STRING),
};
static HashTable func_info;
ZEND_API int zend_func_info_rid = -1;
static uint32_t get_internal_func_info(
const zend_call_info *call_info, const zend_ssa *ssa) {
zend_function *callee_func = call_info->callee_func;
if (callee_func->common.scope) {
/* This is a method, not a function. */
return 0;
}
zval *zv = zend_hash_find_ex(&func_info, callee_func->common.function_name, 1);
if (!zv) {
return 0;
}
func_info_t *info = Z_PTR_P(zv);
if (info->info_func) {
return info->info_func(call_info, ssa);
} else {
return info->info;
}
}
ZEND_API uint32_t zend_get_func_info(
const zend_call_info *call_info, const zend_ssa *ssa,
zend_class_entry **ce, bool *ce_is_instanceof)
{
uint32_t ret = 0;
const zend_function *callee_func = call_info->callee_func;
*ce = NULL;
*ce_is_instanceof = 0;
if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
uint32_t internal_ret = get_internal_func_info(call_info, ssa);
#if !ZEND_DEBUG
if (internal_ret) {
return internal_ret;
}
#endif
ret = zend_get_return_info_from_signature_only(
callee_func, /* script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ !call_info->is_prototype);
#if ZEND_DEBUG
if (internal_ret) {
zend_string *name = callee_func->common.function_name;
/* Check whether the func_info information is a subset of the information we can
* compute from the specified return type, otherwise it contains redundant types. */
if (internal_ret & ~ret) {
fprintf(stderr, "Inaccurate func info for %s()\n", ZSTR_VAL(name));
}
/* Check whether the func info is completely redundant with arginfo. */
if (internal_ret == ret) {
fprintf(stderr, "Useless func info for %s()\n", ZSTR_VAL(name));
}
/* If the return type is not mixed, check that the types match exactly if we exclude
* RC and array information. */
uint32_t ret_any = ret & MAY_BE_ANY, internal_ret_any = internal_ret & MAY_BE_ANY;
if (ret_any != MAY_BE_ANY) {
uint32_t diff = internal_ret_any ^ ret_any;
/* Func info may contain "true" types as well as isolated "null" and "false". */
if (diff && !(diff == MAY_BE_FALSE && (ret & MAY_BE_FALSE))
&& (internal_ret_any & ~(MAY_BE_NULL|MAY_BE_FALSE))) {
fprintf(stderr, "Incorrect func info for %s()\n", ZSTR_VAL(name));
}
}
return internal_ret;
}
#endif
} else {
if (!call_info->is_prototype) {
// FIXME: the order of functions matters!!!
zend_func_info *info = ZEND_FUNC_INFO((zend_op_array*)callee_func);
if (info) {
ret = info->return_info.type;
*ce = info->return_info.ce;
*ce_is_instanceof = info->return_info.is_instanceof;
}
}
if (!ret) {
ret = zend_get_return_info_from_signature_only(
callee_func, /* TODO: script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ !call_info->is_prototype);
}
}
return ret;
}
int zend_func_info_startup(void)
{
size_t i;
if (zend_func_info_rid == -1) {
zend_func_info_rid = zend_get_resource_handle("Zend Optimizer");
if (zend_func_info_rid < 0) {
return FAILURE;
}
zend_hash_init(&func_info, sizeof(func_infos)/sizeof(func_info_t), NULL, NULL, 1);
for (i = 0; i < sizeof(func_infos)/sizeof(func_info_t); i++) {
zend_string *key = zend_string_init_interned(func_infos[i].name, func_infos[i].name_len, 1);
if (zend_hash_add_ptr(&func_info, key, (void**)&func_infos[i]) == NULL) {
fprintf(stderr, "ERROR: Duplicate function info for \"%s\"\n", func_infos[i].name);
}
zend_string_release_ex(key, 1);
}
}
return SUCCESS;
}
int zend_func_info_shutdown(void)
{
if (zend_func_info_rid != -1) {
zend_hash_destroy(&func_info);
zend_func_info_rid = -1;
}
return SUCCESS;
}
-68
View File
@@ -1,68 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_FUNC_INFO_H
#define ZEND_FUNC_INFO_H
#include "zend_ssa.h"
/* func/cfg flags */
#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses variables by name */
#define ZEND_FUNC_HAS_CALLS (1<<1)
#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
#define ZEND_FUNC_NO_LOOPS (1<<3)
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
#define ZEND_FUNC_FREE_LOOP_VAR (1<<5)
#define ZEND_FUNC_RECURSIVE (1<<7)
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
#define ZEND_FUNC_HAS_EXTENDED_FCALL (1<<10)
#define ZEND_FUNC_HAS_EXTENDED_STMT (1<<11)
#define ZEND_SSA_TSSA (1<<12) /* used by tracing JIT */
#define ZEND_FUNC_JIT_ON_FIRST_EXEC (1<<13) /* used by JIT */
#define ZEND_FUNC_JIT_ON_PROF_REQUEST (1<<14) /* used by JIT */
#define ZEND_FUNC_JIT_ON_HOT_COUNTERS (1<<15) /* used by JIT */
#define ZEND_FUNC_JIT_ON_HOT_TRACE (1<<16) /* used by JIT */
typedef struct _zend_func_info zend_func_info;
typedef struct _zend_call_info zend_call_info;
#define ZEND_FUNC_INFO(op_array) \
((zend_func_info*)((op_array)->reserved[zend_func_info_rid]))
#define ZEND_SET_FUNC_INFO(op_array, info) do { \
zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \
*pinfo = info; \
} while (0)
BEGIN_EXTERN_C()
extern ZEND_API int zend_func_info_rid;
ZEND_API uint32_t zend_get_func_info(
const zend_call_info *call_info, const zend_ssa *ssa,
zend_class_entry **ce, bool *ce_is_instanceof);
int zend_func_info_startup(void);
int zend_func_info_shutdown(void);
END_EXTERN_C()
#endif /* ZEND_FUNC_INFO_H */
File diff suppressed because it is too large. Load diff
-291
View File
@@ -1,291 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, e-SSA based Type & Range Inference |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_INFERENCE_H
#define ZEND_INFERENCE_H
#include "zend_optimizer.h"
#include "zend_ssa.h"
#include "zend_bitset.h"
/* Bitmask for type inference (zend_ssa_var_info.type) */
#include "zend_type_info.h"
#define MAY_BE_PACKED_GUARD (1<<27) /* needs packed array guard */
#define MAY_BE_CLASS_GUARD (1<<27) /* needs class guard */
#define MAY_BE_GUARD (1<<28) /* needs type guard */
//#define MAY_BE_IN_REG (1<<29) /* deprecated and not used */
//TODO: remome MAY_BE_RC1, MAY_BE_RCN???
#define MAY_BE_RC1 (1<<30) /* may be non-reference with refcount == 1 */
#define MAY_BE_RCN (1u<<31) /* may be non-reference with refcount > 1 */
#define MAY_HAVE_DTOR \
(MAY_BE_OBJECT|MAY_BE_RESOURCE \
|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE)
#define DEFINE_SSA_OP_HAS_RANGE(opN) \
static zend_always_inline bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
zval *zv = CRT_CONSTANT(opline->opN); \
return (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL); \
} else { \
return (opline->opN##_type != IS_UNUSED && \
ssa->var_info && \
ssa_op->opN##_use >= 0 && \
ssa->var_info[ssa_op->opN##_use].has_range); \
} \
return 0; \
} \
#define DEFINE_SSA_OP_MIN_RANGE(opN) \
static zend_always_inline zend_long _ssa_##opN##_min_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
return 1; \
} else if (Z_TYPE_P(zv) == IS_FALSE) { \
return 0; \
} else if (Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
} else if (opline->opN##_type != IS_UNUSED && \
ssa->var_info && \
ssa_op->opN##_use >= 0 && \
ssa->var_info[ssa_op->opN##_use].has_range) { \
return ssa->var_info[ssa_op->opN##_use].range.min; \
} \
return ZEND_LONG_MIN; \
} \
#define DEFINE_SSA_OP_MAX_RANGE(opN) \
static zend_always_inline zend_long _ssa_##opN##_max_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
return 1; \
} else if (Z_TYPE_P(zv) == IS_FALSE) { \
return 0; \
} else if (Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
} else if (opline->opN##_type != IS_UNUSED && \
ssa->var_info && \
ssa_op->opN##_use >= 0 && \
ssa->var_info[ssa_op->opN##_use].has_range) { \
return ssa->var_info[ssa_op->opN##_use].range.max; \
} \
return ZEND_LONG_MAX; \
} \
#define DEFINE_SSA_OP_RANGE_UNDERFLOW(opN) \
static zend_always_inline char _ssa_##opN##_range_underflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
} else if (opline->opN##_type != IS_UNUSED && \
ssa->var_info && \
ssa_op->opN##_use >= 0 && \
ssa->var_info[ssa_op->opN##_use].has_range) { \
return ssa->var_info[ssa_op->opN##_use].range.underflow; \
} \
return 1; \
} \
#define DEFINE_SSA_OP_RANGE_OVERFLOW(opN) \
static zend_always_inline char _ssa_##opN##_range_overflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
} else if (opline->opN##_type != IS_UNUSED && \
ssa->var_info && \
ssa_op->opN##_use >= 0 && \
ssa->var_info[ssa_op->opN##_use].has_range) { \
return ssa->var_info[ssa_op->opN##_use].range.overflow; \
} \
return 1; \
} \
DEFINE_SSA_OP_HAS_RANGE(op1)
DEFINE_SSA_OP_MIN_RANGE(op1)
DEFINE_SSA_OP_MAX_RANGE(op1)
DEFINE_SSA_OP_RANGE_UNDERFLOW(op1)
DEFINE_SSA_OP_RANGE_OVERFLOW(op1)
DEFINE_SSA_OP_HAS_RANGE(op2)
DEFINE_SSA_OP_MIN_RANGE(op2)
DEFINE_SSA_OP_MAX_RANGE(op2)
DEFINE_SSA_OP_RANGE_UNDERFLOW(op2)
DEFINE_SSA_OP_RANGE_OVERFLOW(op2)
#define OP1_HAS_RANGE() (_ssa_op1_has_range (op_array, ssa, opline, ssa_op))
#define OP1_MIN_RANGE() (_ssa_op1_min_range (op_array, ssa, opline, ssa_op))
#define OP1_MAX_RANGE() (_ssa_op1_max_range (op_array, ssa, opline, ssa_op))
#define OP1_RANGE_UNDERFLOW() (_ssa_op1_range_underflow (op_array, ssa, opline, ssa_op))
#define OP1_RANGE_OVERFLOW() (_ssa_op1_range_overflow (op_array, ssa, opline, ssa_op))
#define OP2_HAS_RANGE() (_ssa_op2_has_range (op_array, ssa, opline, ssa_op))
#define OP2_MIN_RANGE() (_ssa_op2_min_range (op_array, ssa, opline, ssa_op))
#define OP2_MAX_RANGE() (_ssa_op2_max_range (op_array, ssa, opline, ssa_op))
#define OP2_RANGE_UNDERFLOW() (_ssa_op2_range_underflow (op_array, ssa, opline, ssa_op))
#define OP2_RANGE_OVERFLOW() (_ssa_op2_range_overflow (op_array, ssa, opline, ssa_op))
static zend_always_inline uint32_t _const_op_type(const zval *zv) {
if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
} else if (Z_TYPE_P(zv) == IS_ARRAY) {
HashTable *ht = Z_ARRVAL_P(zv);
uint32_t tmp = MAY_BE_ARRAY;
zend_string *str;
zval *val;
if (Z_REFCOUNTED_P(zv)) {
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
} else {
tmp |= MAY_BE_RCN;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
if (str) {
tmp |= MAY_BE_ARRAY_KEY_STRING;
} else {
tmp |= MAY_BE_ARRAY_KEY_LONG;
}
tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
} ZEND_HASH_FOREACH_END();
if (HT_IS_PACKED(ht)) {
tmp &= ~MAY_BE_ARRAY_HASH;
}
return tmp;
} else {
uint32_t tmp = (1 << Z_TYPE_P(zv));
if (Z_REFCOUNTED_P(zv)) {
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
} else if (Z_TYPE_P(zv) == IS_STRING) {
tmp |= MAY_BE_RCN;
}
return tmp;
}
}
static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa_var_num)
{
if (ssa->var_info && ssa_var_num >= 0) {
return ssa->var_info[ssa_var_num].type;
} else {
return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_INDIRECT | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
}
}
#define DEFINE_SSA_OP_INFO(opN) \
static zend_always_inline uint32_t _ssa_##opN##_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
if (opline->opN##_type == IS_CONST) { \
return _const_op_type(CRT_CONSTANT(opline->opN)); \
} else { \
return get_ssa_var_info(ssa, ssa->var_info ? ssa_op->opN##_use : -1); \
} \
} \
#define DEFINE_SSA_OP_DEF_INFO(opN) \
static zend_always_inline uint32_t _ssa_##opN##_def_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
{ \
return get_ssa_var_info(ssa, ssa->var_info ? ssa_op->opN##_def : -1); \
} \
DEFINE_SSA_OP_INFO(op1)
DEFINE_SSA_OP_INFO(op2)
DEFINE_SSA_OP_INFO(result)
DEFINE_SSA_OP_DEF_INFO(op1)
DEFINE_SSA_OP_DEF_INFO(op2)
DEFINE_SSA_OP_DEF_INFO(result)
#define OP1_INFO() (_ssa_op1_info(op_array, ssa, opline, ssa_op))
#define OP2_INFO() (_ssa_op2_info(op_array, ssa, opline, ssa_op))
#define OP1_DATA_INFO() (_ssa_op1_info(op_array, ssa, (opline+1), (ssa_op+1)))
#define OP2_DATA_INFO() (_ssa_op2_info(op_array, ssa, (opline+1), (ssa_op+1)))
#define RES_USE_INFO() (_ssa_result_info(op_array, ssa, opline, ssa_op))
#define OP1_DEF_INFO() (_ssa_op1_def_info(op_array, ssa, opline, ssa_op))
#define OP2_DEF_INFO() (_ssa_op2_def_info(op_array, ssa, opline, ssa_op))
#define OP1_DATA_DEF_INFO() (_ssa_op1_def_info(op_array, ssa, (opline+1), (ssa_op+1)))
#define OP2_DATA_DEF_INFO() (_ssa_op2_def_info(op_array, ssa, (opline+1), (ssa_op+1)))
#define RES_INFO() (_ssa_result_def_info(op_array, ssa, opline, ssa_op))
static zend_always_inline bool zend_add_will_overflow(zend_long a, zend_long b) {
return (b > 0 && a > ZEND_LONG_MAX - b)
|| (b < 0 && a < ZEND_LONG_MIN - b);
}
static zend_always_inline bool zend_sub_will_overflow(zend_long a, zend_long b) {
return (b > 0 && a < ZEND_LONG_MIN + b)
|| (b < 0 && a > ZEND_LONG_MAX + b);
}
BEGIN_EXTERN_C()
ZEND_API int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa);
ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
ZEND_API int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level);
ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert);
int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp);
ZEND_API int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp);
void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, bool underflow, zend_long min, zend_long max, bool overflow);
int zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
int zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level);
ZEND_API uint32_t zend_fetch_arg_info_type(
const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce);
ZEND_API void zend_init_func_return_info(
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret);
uint32_t zend_get_return_info_from_signature_only(
const zend_function *func, const zend_script *script,
zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info);
void zend_func_return_info(const zend_op_array *op_array,
const zend_script *script,
int recursive,
int widening,
zend_ssa_var_info *ret);
ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, uint32_t t1, uint32_t t2);
ZEND_API int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa);
ZEND_API int zend_update_type_info(
const zend_op_array *op_array, zend_ssa *ssa, const zend_script *script,
zend_op *opline, zend_ssa_op *ssa_op, const zend_op **ssa_opcodes,
zend_long optimization_level);
END_EXTERN_C()
#endif /* ZEND_INFERENCE_H */
File diff suppressed because it is too large. Load diff
-98
View File
@@ -1,98 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_OPTIMIZER_H
#define ZEND_OPTIMIZER_H
#include "zend.h"
#include "zend_compile.h"
#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* Simple local optimizations */
#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* */
#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* Jump optimization */
#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5) /* DFA based optimization */
#define ZEND_OPTIMIZER_PASS_7 (1<<6) /* CALL GRAPH optimization */
#define ZEND_OPTIMIZER_PASS_8 (1<<7) /* SCCP (constant propagation) */
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */
#define ZEND_OPTIMIZER_PASS_11 (1<<10) /* Merge equal constants */
#define ZEND_OPTIMIZER_PASS_12 (1<<11) /* Adjust used stack */
#define ZEND_OPTIMIZER_PASS_13 (1<<12) /* Remove unused variables */
#define ZEND_OPTIMIZER_PASS_14 (1<<13) /* DCE (dead code elimination) */
#define ZEND_OPTIMIZER_PASS_15 (1<<14) /* (unsafe) Collect constants */
#define ZEND_OPTIMIZER_PASS_16 (1<<15) /* Inline functions */
#define ZEND_OPTIMIZER_IGNORE_OVERLOADING (1<<16) /* (unsafe) Ignore possibility of operator overloading */
#define ZEND_OPTIMIZER_ALL_PASSES 0x7FFFFFFF
#define DEFAULT_OPTIMIZATION_LEVEL "0x7FFEBFFF"
#define ZEND_DUMP_AFTER_PASS_1 ZEND_OPTIMIZER_PASS_1
#define ZEND_DUMP_AFTER_PASS_2 ZEND_OPTIMIZER_PASS_2
#define ZEND_DUMP_AFTER_PASS_3 ZEND_OPTIMIZER_PASS_3
#define ZEND_DUMP_AFTER_PASS_4 ZEND_OPTIMIZER_PASS_4
#define ZEND_DUMP_AFTER_PASS_5 ZEND_OPTIMIZER_PASS_5
#define ZEND_DUMP_AFTER_PASS_6 ZEND_OPTIMIZER_PASS_6
#define ZEND_DUMP_AFTER_PASS_7 ZEND_OPTIMIZER_PASS_7
#define ZEND_DUMP_AFTER_PASS_8 ZEND_OPTIMIZER_PASS_8
#define ZEND_DUMP_AFTER_PASS_9 ZEND_OPTIMIZER_PASS_9
#define ZEND_DUMP_AFTER_PASS_10 ZEND_OPTIMIZER_PASS_10
#define ZEND_DUMP_AFTER_PASS_11 ZEND_OPTIMIZER_PASS_11
#define ZEND_DUMP_AFTER_PASS_12 ZEND_OPTIMIZER_PASS_12
#define ZEND_DUMP_AFTER_PASS_13 ZEND_OPTIMIZER_PASS_13
#define ZEND_DUMP_AFTER_PASS_14 ZEND_OPTIMIZER_PASS_14
#define ZEND_DUMP_BEFORE_OPTIMIZER (1<<16)
#define ZEND_DUMP_AFTER_OPTIMIZER (1<<17)
#define ZEND_DUMP_BEFORE_BLOCK_PASS (1<<18)
#define ZEND_DUMP_AFTER_BLOCK_PASS (1<<19)
#define ZEND_DUMP_BLOCK_PASS_VARS (1<<20)
#define ZEND_DUMP_BEFORE_DFA_PASS (1<<21)
#define ZEND_DUMP_AFTER_DFA_PASS (1<<22)
#define ZEND_DUMP_DFA_CFG (1<<23)
#define ZEND_DUMP_DFA_DOMINATORS (1<<24)
#define ZEND_DUMP_DFA_LIVENESS (1<<25)
#define ZEND_DUMP_DFA_PHI (1<<26)
#define ZEND_DUMP_DFA_SSA (1<<27)
#define ZEND_DUMP_DFA_SSA_VARS (1<<28)
#define ZEND_DUMP_SCCP (1<<29)
typedef struct _zend_script {
zend_string *filename;
zend_op_array main_op_array;
HashTable function_table;
HashTable class_table;
uint32_t first_early_binding_opline; /* the linked list of delayed declarations */
} zend_script;
BEGIN_EXTERN_C()
ZEND_API int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level);
int zend_optimizer_startup(void);
int zend_optimizer_shutdown(void);
END_EXTERN_C()
#endif
-123
View File
@@ -1,123 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_OPTIMIZER_INTERNAL_H
#define ZEND_OPTIMIZER_INTERNAL_H
#include "zend_ssa.h"
#include "zend_func_info.h"
#define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant]
#define ZEND_OP1_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op1)
#define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant]
#define ZEND_OP2_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op2)
#define VAR_NUM(v) EX_VAR_TO_NUM(v)
#define NUM_VAR(v) EX_NUM_TO_VAR(v)
#define INV_COND(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ : ZEND_JMPZ)
#define INV_EX_COND(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ : ZEND_JMPZ)
#define INV_COND_EX(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX)
#define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX)
#define RESULT_UNUSED(op) (op->result_type == IS_UNUSED)
#define SAME_VAR(op1, op2) (op1 ## _type == op2 ## _type && op1.var == op2.var)
typedef struct _zend_optimizer_ctx {
zend_arena *arena;
zend_script *script;
HashTable *constants;
zend_long optimization_level;
zend_long debug_level;
} zend_optimizer_ctx;
#define LITERAL_LONG(op, val) do { \
zval _c; \
ZVAL_LONG(&_c, val); \
op.constant = zend_optimizer_add_literal(op_array, &_c); \
} while (0)
#define LITERAL_BOOL(op, val) do { \
zval _c; \
ZVAL_BOOL(&_c, val); \
op.constant = zend_optimizer_add_literal(op_array, &_c); \
} while (0)
#define literal_dtor(zv) do { \
zval_ptr_dtor_nogc(zv); \
ZVAL_NULL(zv); \
} while (0)
#define COPY_NODE(target, src) do { \
target ## _type = src ## _type; \
target = src; \
} while (0)
static inline bool zend_optimizer_is_loop_var_free(const zend_op *opline) {
return (opline->opcode == ZEND_FE_FREE && opline->extended_value != ZEND_FREE_ON_RETURN)
|| (opline->opcode == ZEND_FREE && opline->extended_value == ZEND_FREE_SWITCH);
}
int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv);
int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy);
void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value);
int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value);
int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2);
int zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1);
int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1);
int zend_optimizer_eval_strlen(zval *result, zval *op1);
int zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
int zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val);
int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uchar type,
uint32_t var,
zval *val);
zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline);
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx);
int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa);
void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map);
void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_compact_vars(zend_op_array *op_array);
zend_function *zend_optimizer_get_called_func(
zend_script *script, zend_op_array *op_array, zend_op *opline, bool *is_prototype);
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline);
void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist);
int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map);
int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects);
int zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, zend_ssa *ssa);
typedef void (*zend_op_array_func_t)(zend_op_array *, void *context);
void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context);
#endif
File diff suppressed because it is too large. Load diff
-326
View File
@@ -1,326 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine, SSA - Static Single Assignment Form |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_SSA_H
#define ZEND_SSA_H
#include "zend_optimizer.h"
#include "zend_cfg.h"
typedef struct _zend_ssa_range {
zend_long min;
zend_long max;
bool underflow;
bool overflow;
} zend_ssa_range;
typedef enum _zend_ssa_negative_lat {
NEG_NONE = 0,
NEG_INIT = 1,
NEG_INVARIANT = 2,
NEG_USE_LT = 3,
NEG_USE_GT = 4,
NEG_UNKNOWN = 5
} zend_ssa_negative_lat;
/* Special kind of SSA Phi function used in eSSA */
typedef struct _zend_ssa_range_constraint {
zend_ssa_range range; /* simple range constraint */
int min_var;
int max_var;
int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */
int max_ssa_var; /* ((max_var>0) ? MAX(ssa_var) : 0) + range.max */
zend_ssa_negative_lat negative;
} zend_ssa_range_constraint;
typedef struct _zend_ssa_type_constraint {
uint32_t type_mask; /* Type mask to intersect with */
zend_class_entry *ce; /* Class entry for instanceof constraints */
} zend_ssa_type_constraint;
typedef union _zend_ssa_pi_constraint {
zend_ssa_range_constraint range;
zend_ssa_type_constraint type;
} zend_ssa_pi_constraint;
/* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */
typedef struct _zend_ssa_phi zend_ssa_phi;
struct _zend_ssa_phi {
zend_ssa_phi *next; /* next Phi in the same BB */
int pi; /* if >= 0 this is actually a e-SSA Pi */
zend_ssa_pi_constraint constraint; /* e-SSA Pi constraint */
int var; /* Original CV, VAR or TMP variable index */
int ssa_var; /* SSA variable index */
int block; /* current BB index */
int visited : 1; /* flag to avoid recursive processing */
int has_range_constraint : 1;
zend_ssa_phi **use_chains;
zend_ssa_phi *sym_use_chain;
int *sources; /* Array of SSA IDs that produce this var.
As many as this block has
predecessors. */
};
typedef struct _zend_ssa_block {
zend_ssa_phi *phis;
} zend_ssa_block;
typedef struct _zend_ssa_op {
int op1_use;
int op2_use;
int result_use;
int op1_def;
int op2_def;
int result_def;
int op1_use_chain;
int op2_use_chain;
int res_use_chain;
} zend_ssa_op;
typedef enum _zend_ssa_alias_kind {
NO_ALIAS,
SYMTABLE_ALIAS,
HTTP_RESPONSE_HEADER_ALIAS
} zend_ssa_alias_kind;
typedef enum _zend_ssa_escape_state {
ESCAPE_STATE_UNKNOWN,
ESCAPE_STATE_NO_ESCAPE,
ESCAPE_STATE_FUNCTION_ESCAPE,
ESCAPE_STATE_GLOBAL_ESCAPE
} zend_ssa_escape_state;
typedef struct _zend_ssa_var {
int var; /* original var number; op.var for CVs and following numbers for VARs and TMP_VARs */
int scc; /* strongly connected component */
int definition; /* opcode that defines this value */
zend_ssa_phi *definition_phi; /* phi that defines this value */
int use_chain; /* uses of this value, linked through opN_use_chain */
zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */
zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constraints */
unsigned int no_val : 1; /* value doesn't matter (used as op1 in ZEND_ASSIGN) */
unsigned int scc_entry : 1;
unsigned int alias : 2; /* value may be changed indirectly */
unsigned int escape_state : 2;
} zend_ssa_var;
typedef struct _zend_ssa_var_info {
uint32_t type; /* inferred type (see zend_inference.h) */
zend_ssa_range range;
zend_class_entry *ce;
unsigned int has_range : 1;
unsigned int is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */
unsigned int recursive : 1;
unsigned int use_as_double : 1;
unsigned int delayed_fetch_this : 1;
unsigned int avoid_refcounting : 1;
unsigned int guarded_reference : 1;
unsigned int indirect_reference : 1; /* IS_INDIRECT returned by FETCH_DIM_W/FETCH_OBJ_W */
} zend_ssa_var_info;
typedef struct _zend_ssa {
zend_cfg cfg; /* control flow graph */
int vars_count; /* number of SSA variables */
int sccs; /* number of SCCs */
zend_ssa_block *blocks; /* array of SSA blocks */
zend_ssa_op *ops; /* array of SSA instructions */
zend_ssa_var *vars; /* use/def chain of SSA variables */
zend_ssa_var_info *var_info;
} zend_ssa;
BEGIN_EXTERN_C()
ZEND_API int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa);
ZEND_API int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa);
ZEND_API int zend_ssa_rename_op(const zend_op_array *op_array, const zend_op *opline, uint32_t k, uint32_t build_flags, int ssa_vars_count, zend_ssa_op *ssa_ops, int *var);
int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var);
void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to);
void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op);
void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi);
void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num);
void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int b);
void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, bool update_types);
static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var)
{
ZEND_ASSERT(var->definition >= 0);
ZEND_ASSERT(var->use_chain < 0);
ZEND_ASSERT(!var->phi_use_chain);
var->definition = -1;
}
static zend_always_inline void zend_ssa_remove_result_def(zend_ssa *ssa, zend_ssa_op *ssa_op)
{
zend_ssa_var *var = &ssa->vars[ssa_op->result_def];
_zend_ssa_remove_def(var);
ssa_op->result_def = -1;
}
static zend_always_inline void zend_ssa_remove_op1_def(zend_ssa *ssa, zend_ssa_op *ssa_op)
{
zend_ssa_var *var = &ssa->vars[ssa_op->op1_def];
_zend_ssa_remove_def(var);
ssa_op->op1_def = -1;
}
static zend_always_inline void zend_ssa_remove_op2_def(zend_ssa *ssa, zend_ssa_op *ssa_op)
{
zend_ssa_var *var = &ssa->vars[ssa_op->op2_def];
_zend_ssa_remove_def(var);
ssa_op->op2_def = -1;
}
END_EXTERN_C()
static zend_always_inline int zend_ssa_next_use(const zend_ssa_op *ssa_op, int var, int use)
{
ssa_op += use;
if (ssa_op->op1_use == var) {
return ssa_op->op1_use_chain;
} else if (ssa_op->op2_use == var) {
return ssa_op->op2_use_chain;
} else {
return ssa_op->res_use_chain;
}
}
static zend_always_inline zend_ssa_phi* zend_ssa_next_use_phi(const zend_ssa *ssa, int var, const zend_ssa_phi *p)
{
if (p->pi >= 0) {
return p->use_chains[0];
} else {
int j;
for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
if (p->sources[j] == var) {
return p->use_chains[j];
}
}
}
return NULL;
}
static zend_always_inline bool zend_ssa_is_no_val_use(const zend_op *opline, const zend_ssa_op *ssa_op, int var)
{
if (opline->opcode == ZEND_ASSIGN
|| opline->opcode == ZEND_UNSET_CV
|| opline->opcode == ZEND_BIND_GLOBAL
|| opline->opcode == ZEND_BIND_STATIC) {
return ssa_op->op1_use == var && ssa_op->op2_use != var;
}
if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
return ssa_op->op2_use == var && ssa_op->op1_use != var;
}
if (ssa_op->result_use == var
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
&& opline->opcode != ZEND_ADD_ARRAY_UNPACK) {
return ssa_op->op1_use != var && ssa_op->op2_use != var;
}
return 0;
}
static zend_always_inline void zend_ssa_rename_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op) {
/* Rename def to use if possible. Mark variable as not defined otherwise. */
if (ssa_op->op1_def >= 0) {
if (ssa_op->op1_use >= 0) {
zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, 1);
}
ssa->vars[ssa_op->op1_def].definition = -1;
ssa_op->op1_def = -1;
}
if (ssa_op->op2_def >= 0) {
if (ssa_op->op2_use >= 0) {
zend_ssa_rename_var_uses(ssa, ssa_op->op2_def, ssa_op->op2_use, 1);
}
ssa->vars[ssa_op->op2_def].definition = -1;
ssa_op->op2_def = -1;
}
if (ssa_op->result_def >= 0) {
if (ssa_op->result_use >= 0) {
zend_ssa_rename_var_uses(ssa, ssa_op->result_def, ssa_op->result_use, 1);
}
ssa->vars[ssa_op->result_def].definition = -1;
ssa_op->result_def = -1;
}
}
#define NUM_PHI_SOURCES(phi) \
((phi)->pi >= 0 ? 1 : (ssa->cfg.blocks[(phi)->block].predecessors_count))
/* FOREACH_USE and FOREACH_PHI_USE explicitly support "continue"
* and changing the use chain of the current element */
#define FOREACH_USE(var, use) do { \
int _var_num = (var) - ssa->vars, next; \
for (use = (var)->use_chain; use >= 0; use = next) { \
next = zend_ssa_next_use(ssa->ops, _var_num, use);
#define FOREACH_USE_END() \
} \
} while (0)
#define FOREACH_PHI_USE(var, phi) do { \
int _var_num = (var) - ssa->vars; \
zend_ssa_phi *next_phi; \
for (phi = (var)->phi_use_chain; phi; phi = next_phi) { \
next_phi = zend_ssa_next_use_phi(ssa, _var_num, phi);
#define FOREACH_PHI_USE_END() \
} \
} while (0)
#define FOREACH_PHI_SOURCE(phi, source) do { \
zend_ssa_phi *_phi = (phi); \
int _i, _end = NUM_PHI_SOURCES(phi); \
for (_i = 0; _i < _end; _i++) { \
ZEND_ASSERT(_phi->sources[_i] >= 0); \
source = _phi->sources[_i];
#define FOREACH_PHI_SOURCE_END() \
} \
} while (0)
#define FOREACH_PHI(phi) do { \
int _i; \
for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \
phi = ssa->blocks[_i].phis; \
for (; phi; phi = phi->next) {
#define FOREACH_PHI_END() \
} \
} \
} while (0)
#define FOREACH_BLOCK(block) do { \
int _i; \
for (_i = 0; _i < ssa->cfg.blocks_count; _i++) { \
(block) = &ssa->cfg.blocks[_i]; \
if (!((block)->flags & ZEND_BB_REACHABLE)) { \
continue; \
}
#define FOREACH_BLOCK_END() \
} \
} while (0)
/* Does not support "break" */
#define FOREACH_INSTR_NUM(i) do { \
zend_basic_block *_block; \
FOREACH_BLOCK(_block) { \
uint32_t _end = _block->start + _block->len; \
for ((i) = _block->start; (i) < _end; (i)++) {
#define FOREACH_INSTR_NUM_END() \
} \
} FOREACH_BLOCK_END(); \
} while (0)
#endif /* ZEND_SSA_H */
-121
View File
@@ -1,121 +0,0 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andy Wingo <wingo@igalia.com> |
+----------------------------------------------------------------------+
*/
#ifndef _ZEND_WORKLIST_H_
#define _ZEND_WORKLIST_H_
#include "zend_arena.h"
#include "zend_bitset.h"
typedef struct _zend_worklist_stack {
int *buf;
int len;
int capacity;
} zend_worklist_stack;
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \
(s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \
(s)->len = 0; \
(s)->capacity = _len; \
} while (0)
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \
free_alloca((s)->buf, use_heap)
static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len)
{
ZEND_ASSERT(len >= 0);
stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len);
stack->len = 0;
stack->capacity = len;
return SUCCESS;
}
static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i)
{
ZEND_ASSERT(stack->len < stack->capacity);
stack->buf[stack->len++] = i;
}
static inline int zend_worklist_stack_peek(zend_worklist_stack *stack)
{
ZEND_ASSERT(stack->len);
return stack->buf[stack->len - 1];
}
static inline int zend_worklist_stack_pop(zend_worklist_stack *stack)
{
ZEND_ASSERT(stack->len);
return stack->buf[--stack->len];
}
typedef struct _zend_worklist {
zend_bitset visited;
zend_worklist_stack stack;
} zend_worklist;
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
(w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
(w)->stack.len = 0; \
(w)->stack.capacity = _len; \
(w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
} while (0)
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \
free_alloca((w)->stack.buf, use_heap)
static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len)
{
ZEND_ASSERT(len >= 0);
worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len));
return zend_worklist_stack_prepare(arena, &worklist->stack, len);
}
static inline int zend_worklist_len(zend_worklist *worklist)
{
return worklist->stack.len;
}
static inline int zend_worklist_push(zend_worklist *worklist, int i)
{
ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity);
if (zend_bitset_in(worklist->visited, i)) {
return 0;
}
zend_bitset_incl(worklist->visited, i);
zend_worklist_stack_push(&worklist->stack, i);
return 1;
}
static inline int zend_worklist_peek(zend_worklist *worklist)
{
return zend_worklist_stack_peek(&worklist->stack);
}
static inline int zend_worklist_pop(zend_worklist *worklist)
{
/* Does not clear visited flag */
return zend_worklist_stack_pop(&worklist->stack);
}
#endif /* _ZEND_WORKLIST_H_ */
-139
View File
@@ -1,139 +0,0 @@
# Zend Engine
## Zend memory manager
### General
The goal of the new memory manager (available since PHP 5.2) is to reduce memory
allocation overhead and speedup memory management.
### Debugging
Normal:
```bash
sapi/cli/php -r 'leak();'
```
Zend MM disabled:
```bash
USE_ZEND_ALLOC=0 valgrind --leak-check=full sapi/cli/php -r 'leak();'
```
### Shared extensions
Since PHP 5.3.11 it is possible to prevent shared extensions from unloading so
that valgrind can correctly track the memory leaks in shared extensions. For
this there is the `ZEND_DONT_UNLOAD_MODULES` environment variable. If set, then
`DL_UNLOAD()` is skipped during the shutdown of shared extensions.
## ZEND_VM
`ZEND_VM` architecture allows specializing opcode handlers according to
`op_type` fields and using different execution methods (call threading, switch
threading and direct threading). As a result ZE2 got more than 20% speedup on
raw PHP code execution (with specialized executor and direct threading execution
method). As in most PHP applications raw execution speed isn't the limiting
factor but system calls and database calls are, your mileage with this patch
will vary.
Most parts of the old zend_execute.c go into `zend_vm_def.h`. Here you can find
opcode handlers and helpers. The typical opcode handler template looks like
this:
```c
ZEND_VM_HANDLER(<OPCODE-NUMBER>, <OPCODE>, <OP1_TYPES>, <OP2_TYPES>)
{
<HANDLER'S CODE>
}
```
`<OPCODE-NUMBER>` is a opcode number (0, 1, ...)
`<OPCODE>` is an opcode name (ZEN_NOP, ZEND_ADD, :)
`<OP1_TYPES>` and `<OP2_TYPES>` are masks for allowed operand op_types.
Specializer will generate code only for defined combination of types. You can
use any combination of the following op_types UNUSED, CONST, VAR, TMP and CV
also you can use ANY mask to disable specialization according operand's op_type.
`<HANDLER'S CODE>` is a handler's code itself. For most handlers it stills the
same as in old `zend_execute.c`, but now it uses macros to access opcode
operands and some internal executor data.
You can see the conformity of new macros to old code in the following list:
```c
EXECUTE_DATA
execute_data
ZEND_VM_DISPATCH_TO_HANDLER(<OP>)
return <OP>_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
ZEND_VM_DISPATCH_TO_HELPER(<NAME>)
return <NAME>(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
ZEND_VM_DISPATCH_TO_HELPER_EX(<NAME>,<PARAM>,<VAL>)
return <NAME>(<VAL>, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
ZEND_VM_CONTINUE()
return 0
ZEND_VM_NEXT_OPCODE()
NEXT_OPCODE()
ZEND_VM_SET_OPCODE(<TARGET>
SET_OPCODE(<TARGET>
ZEND_VM_INC_OPCODE()
INC_OPCOD()
ZEND_VM_RETURN_FROM_EXECUTE_LOOP()
RETURN_FROM_EXECUTE_LOOP()
ZEND_VM_C_LABEL(<LABEL>):
<LABEL>:
ZEND_VM_C_GOTO(<LABEL>)
goto <LABEL>
OP<X>_TYPE
opline->op<X>.op_type
GET_OP<X>_ZVAL_PTR(<TYPE>)
get_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
GET_OP<X>_ZVAL_PTR_PTR(<TYPE>)
get_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
GET_OP<X>_OBJ_ZVAL_PTR(<TYPE>)
get_obj_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
GET_OP<X>_OBJ_ZVAL_PTR_PTR(<TYPE>)
get_obj_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
IS_OP<X>_TMP_FREE()
IS_TMP_FREE(free_op<X>)
FREE_OP<X>()
FREE_OP(free_op<X>)
FREE_OP<X>_IF_VAR()
FREE_VAR(free_op<X>)
FREE_OP<X>_VAR_PTR()
FREE_VAR_PTR(free_op<X>)
```
Executor's helpers can be defined without parameters or with one parameter. This
is done with the following constructs:
```c
ZEND_VM_HELPER(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>)
{
<HELPER'S CODE>
}
ZEND_VM_HELPER_EX(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>, <PARAM_SPEC>)
{
<HELPER'S CODE>
}
```
Executor's code is generated by PHP script zend_vm_gen.php it uses
`zend_vm_def.h` and `zend_vm_execute.skl` as input and produces
`zend_vm_opcodes.h` and `zend_vm_execute.h`. The first file is a list of opcode
definitions. It is included from `zend_compile.h`. The second one is an executor
code itself. It is included from `zend_execute.c`.
`zend_vm_gen.php` can produce different kind of executors. You can select
different opcode threading model using `--with-vm-kind=CALL|SWITCH|GOTO`. You
can disable opcode specialization using `--without-specializer`. You can include
or exclude old executor together with specialized one using
`--without-old-executor`. At last you can debug executor using original
`zend_vm_def.h` or generated file `zend_vm_execute.h`. Debugging with original
file requires `--with-lines` option. By default ZE2 uses the following command
to generate executor:
```bash
php zend_vm_gen.php --with-vm-kind=CALL
```
-388
View File
@@ -1,388 +0,0 @@
dnl This file contains Zend specific autoconf macros.
dnl
dnl ZEND_CHECK_FLOAT_PRECISION
dnl
dnl x87 floating point internal precision control checks
dnl See: http://wiki.php.net/rfc/rounding
dnl
AC_DEFUN([ZEND_CHECK_FLOAT_PRECISION],[
AC_MSG_CHECKING([for usable _FPU_SETCW])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <fpu_control.h>
]],[[
fpu_control_t fpu_oldcw, fpu_cw;
volatile double result;
double a = 2877.0;
volatile double b = 1000000.0;
_FPU_GETCW(fpu_oldcw);
fpu_cw = (fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE;
_FPU_SETCW(fpu_cw);
result = a / b;
_FPU_SETCW(fpu_oldcw);
]])],[ac_cfp_have__fpu_setcw=yes],[ac_cfp_have__fpu_setcw=no])
if test "$ac_cfp_have__fpu_setcw" = "yes" ; then
AC_DEFINE(HAVE__FPU_SETCW, 1, [whether _FPU_SETCW is present and usable])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([for usable fpsetprec])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <machine/ieeefp.h>
]],[[
fp_prec_t fpu_oldprec;
volatile double result;
double a = 2877.0;
volatile double b = 1000000.0;
fpu_oldprec = fpgetprec();
fpsetprec(FP_PD);
result = a / b;
fpsetprec(fpu_oldprec);
]])], [ac_cfp_have_fpsetprec=yes], [ac_cfp_have_fpsetprec=no])
if test "$ac_cfp_have_fpsetprec" = "yes" ; then
AC_DEFINE(HAVE_FPSETPREC, 1, [whether fpsetprec is present and usable])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([for usable _controlfp])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <float.h>
]],[[
unsigned int fpu_oldcw;
volatile double result;
double a = 2877.0;
volatile double b = 1000000.0;
fpu_oldcw = _controlfp(0, 0);
_controlfp(_PC_53, _MCW_PC);
result = a / b;
_controlfp(fpu_oldcw, _MCW_PC);
]])], [ac_cfp_have__controlfp=yes], [ac_cfp_have__controlfp=no])
if test "$ac_cfp_have__controlfp" = "yes" ; then
AC_DEFINE(HAVE__CONTROLFP, 1, [whether _controlfp is present usable])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([for usable _controlfp_s])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <float.h>
]],[[
unsigned int fpu_oldcw, fpu_cw;
volatile double result;
double a = 2877.0;
volatile double b = 1000000.0;
_controlfp_s(&fpu_cw, 0, 0);
fpu_oldcw = fpu_cw;
_controlfp_s(&fpu_cw, _PC_53, _MCW_PC);
result = a / b;
_controlfp_s(&fpu_cw, fpu_oldcw, _MCW_PC);
]])], [ac_cfp_have__controlfp_s=yes], [ac_cfp_have__controlfp_s=no])
if test "$ac_cfp_have__controlfp_s" = "yes" ; then
AC_DEFINE(HAVE__CONTROLFP_S, 1, [whether _controlfp_s is present and usable])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([whether FPU control word can be manipulated by inline assembler])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
/* nothing */
]],[[
unsigned int oldcw, cw;
volatile double result;
double a = 2877.0;
volatile double b = 1000000.0;
__asm__ __volatile__ ("fnstcw %0" : "=m" (*&oldcw));
cw = (oldcw & ~0x0 & ~0x300) | 0x200;
__asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
result = a / b;
__asm__ __volatile__ ("fldcw %0" : : "m" (*&oldcw));
]])], [ac_cfp_have_fpu_inline_asm_x86=yes], [ac_cfp_have_fpu_inline_asm_x86=no])
if test "$ac_cfp_have_fpu_inline_asm_x86" = "yes" ; then
AC_DEFINE(HAVE_FPU_INLINE_ASM_X86, 1, [whether FPU control word can be manipulated by inline assembler])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
])
dnl
dnl LIBZEND_BASIC_CHECKS
dnl
dnl Basic checks specific for the Zend engine library.
dnl
AC_DEFUN([LIBZEND_BASIC_CHECKS],[
AC_REQUIRE([AC_PROG_CC])
AC_CHECK_HEADERS([cpuid.h])
dnl
dnl LIBZEND_DLSYM_CHECK
dnl
dnl Ugly hack to check if dlsym() requires a leading underscore in symbol name.
dnl
AC_DEFUN([LIBZEND_DLSYM_CHECK],[
AC_MSG_CHECKING([whether dlsym() requires a leading underscore in symbol names])
_LT_AC_TRY_DLOPEN_SELF([
AC_MSG_RESULT(no)
], [
AC_MSG_RESULT(yes)
AC_DEFINE(DLSYM_NEEDS_UNDERSCORE, 1, [Define if dlsym() requires a leading underscore in symbol names. ])
], [
AC_MSG_RESULT(no)
], [])
])
dnl Checks for library functions.
AC_CHECK_FUNCS(getpid kill sigsetjmp)
ZEND_CHECK_FLOAT_PRECISION
dnl Test whether double cast to long preserves least significant bits.
AC_MSG_CHECKING(whether double cast to long preserves least significant bits)
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <limits.h>
#include <stdlib.h>
int main()
{
if (sizeof(long) == 4) {
double d = (double) LONG_MIN * LONG_MIN + 2e9;
if ((long) d == 2e9 && (long) -d == -2e9) {
return 0;
}
} else if (sizeof(long) == 8) {
double correct = 18e18 - ((double) LONG_MIN * -2); /* Subtract ULONG_MAX + 1 */
if ((long) 18e18 == correct) { /* On 64-bit, only check between LONG_MAX and ULONG_MAX */
return 0;
}
}
return 1;
}
]])], [
AC_DEFINE([ZEND_DVAL_TO_LVAL_CAST_OK], 1, [Define if double cast to long preserves least significant bits])
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
], [
AC_MSG_RESULT(no)
])
])
dnl
dnl LIBZEND_OTHER_CHECKS
dnl
AC_DEFUN([LIBZEND_OTHER_CHECKS],[
AC_MSG_CHECKING(whether to enable thread-safety)
AC_MSG_RESULT($ZEND_ZTS)
AC_MSG_CHECKING(whether to enable Zend debugging)
AC_MSG_RESULT($ZEND_DEBUG)
if test "$ZEND_DEBUG" = "yes"; then
AC_DEFINE(ZEND_DEBUG,1,[ ])
echo " $CFLAGS" | grep ' -g' >/dev/null || DEBUG_CFLAGS="-g"
if test "$CFLAGS" = "-g -O2"; then
CFLAGS=-g
fi
else
AC_DEFINE(ZEND_DEBUG,0,[ ])
fi
test -n "$GCC" && CFLAGS="-Wall -Wextra -Wno-strict-aliasing -Wno-unused-parameter -Wno-sign-compare $CFLAGS"
dnl Check if compiler supports -Wno-clobbered (only GCC)
AX_CHECK_COMPILE_FLAG([-Wno-clobbered], CFLAGS="-Wno-clobbered $CFLAGS", , [-Werror])
dnl Check for support for implicit fallthrough level 1, also add after previous CFLAGS as level 3 is enabled in -Wextra
AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough=1], CFLAGS="$CFLAGS -Wimplicit-fallthrough=1", , [-Werror])
AX_CHECK_COMPILE_FLAG([-Wduplicated-cond], CFLAGS="-Wduplicated-cond $CFLAGS", , [-Werror])
AX_CHECK_COMPILE_FLAG([-Wlogical-op], CFLAGS="-Wlogical-op $CFLAGS", , [-Werror])
AX_CHECK_COMPILE_FLAG([-Wformat-truncation], CFLAGS="-Wformat-truncation $CFLAGS", , [-Werror])
AX_CHECK_COMPILE_FLAG([-Wstrict-prototypes], CFLAGS="-Wstrict-prototypes $CFLAGS", , [-Werror])
AX_CHECK_COMPILE_FLAG([-fno-common], CFLAGS="-fno-common $CFLAGS", , [-Werror])
test -n "$DEBUG_CFLAGS" && CFLAGS="$CFLAGS $DEBUG_CFLAGS"
if test "$ZEND_ZTS" = "yes"; then
AC_DEFINE(ZTS,1,[ ])
CFLAGS="$CFLAGS -DZTS"
fi
AC_C_INLINE
AC_MSG_CHECKING(target system is Darwin)
if echo "$target" | grep "darwin" > /dev/null; then
AC_DEFINE([DARWIN], 1, [Define if the target system is darwin])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
dnl Test and set the alignment define for ZEND_MM. This also does the
dnl logarithmic test for ZEND_MM.
AC_MSG_CHECKING(for MM alignment and log values)
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
#include <stdlib.h>
typedef union _mm_align_test {
void *ptr;
double dbl;
long lng;
} mm_align_test;
#if (defined (__GNUC__) && __GNUC__ >= 2)
#define ZEND_MM_ALIGNMENT (__alignof__ (mm_align_test))
#else
#define ZEND_MM_ALIGNMENT (sizeof(mm_align_test))
#endif
int main()
{
int i = ZEND_MM_ALIGNMENT;
int zeros = 0;
FILE *fp;
while (i & ~0x1) {
zeros++;
i = i >> 1;
}
fp = fopen("conftest.zend", "w");
fprintf(fp, "%d %d\n", ZEND_MM_ALIGNMENT, zeros);
fclose(fp);
return 0;
}
]])], [
LIBZEND_MM_ALIGN=`cat conftest.zend | cut -d ' ' -f 1`
LIBZEND_MM_ALIGN_LOG2=`cat conftest.zend | cut -d ' ' -f 2`
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT, $LIBZEND_MM_ALIGN, [ ])
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT_LOG2, $LIBZEND_MM_ALIGN_LOG2, [ ])
], [], [
dnl Cross compilation needs something here.
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT, 8, [ ])
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT_LOG2, 3, [ ])
])
AC_MSG_RESULT(done)
AC_CHECK_FUNCS(mremap)
AC_ARG_ENABLE([zend-signals],
[AS_HELP_STRING([--disable-zend-signals],
[whether to enable zend signal handling])],
[ZEND_SIGNALS=$enableval],
[ZEND_SIGNALS=yes])
AC_CHECK_FUNCS([sigaction], [], [
ZEND_SIGNALS=no
])
if test "$ZEND_SIGNALS" = "yes"; then
AC_DEFINE(ZEND_SIGNALS, 1, [Use zend signal handling])
CFLAGS="$CFLAGS -DZEND_SIGNALS"
fi
AC_MSG_CHECKING(whether to enable zend signal handling)
AC_MSG_RESULT($ZEND_SIGNALS)
])
AC_MSG_CHECKING(whether /dev/urandom exists)
if test -r "/dev/urandom" && test -c "/dev/urandom"; then
AC_DEFINE([HAVE_DEV_URANDOM], 1, [Define if the target system has /dev/urandom device])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_ARG_ENABLE([gcc-global-regs],
[AS_HELP_STRING([--disable-gcc-global-regs],
[whether to enable GCC global register variables])],
[ZEND_GCC_GLOBAL_REGS=$enableval],
[ZEND_GCC_GLOBAL_REGS=yes])
AC_MSG_CHECKING(for global register variables support)
if test "$ZEND_GCC_GLOBAL_REGS" != "no"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if defined(__GNUC__)
# define ZEND_GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#else
# define ZEND_GCC_VERSION 0
#endif
#if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"
# define ZEND_VM_IP_GLOBAL_REG "%edi"
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
# define ZEND_VM_FP_GLOBAL_REG "%r14"
# define ZEND_VM_IP_GLOBAL_REG "%r15"
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
#elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__)
# define ZEND_VM_FP_GLOBAL_REG "x27"
# define ZEND_VM_IP_GLOBAL_REG "x28"
#else
# error "global register variables are not supported"
#endif
typedef int (*opcode_handler_t)(void);
register void *FP __asm__(ZEND_VM_FP_GLOBAL_REG);
register const opcode_handler_t *IP __asm__(ZEND_VM_IP_GLOBAL_REG);
int emu(const opcode_handler_t *ip, void *fp) {
const opcode_handler_t *orig_ip = IP;
void *orig_fp = FP;
IP = ip;
FP = fp;
while ((*ip)());
FP = orig_fp;
IP = orig_ip;
}
]], [[
]])], [
ZEND_GCC_GLOBAL_REGS=yes
], [
ZEND_GCC_GLOBAL_REGS=no
])
fi
if test "$ZEND_GCC_GLOBAL_REGS" = "yes"; then
AC_DEFINE([HAVE_GCC_GLOBAL_REGS], 1, [Define if the target system has support for global register variables])
else
HAVE_GCC_GLOBAL_REGS=no
fi
AC_MSG_RESULT($ZEND_GCC_GLOBAL_REGS)
dnl Check whether __cpuid_count is available.
AC_CACHE_CHECK(whether __cpuid_count is available, ac_cv_cpuid_count_available, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <cpuid.h>
]], [[
unsigned eax, ebx, ecx, edx;
__cpuid_count(0, 0, eax, ebx, ecx, edx);
]])], [
ac_cv_cpuid_count_available=yes
], [
ac_cv_cpuid_count_available=no
])])
if test "$ac_cv_cpuid_count_available" = "yes"; then
AC_DEFINE([HAVE_CPUID_COUNT], 1, [whether __cpuid_count is available])
fi
-23
View File
@@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-114
View File
@@ -1,114 +0,0 @@
/*
Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | d8 | d9 | d10 | d11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | d12 | d13 | d14 | d15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | x19 | x20 | x21 | x22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | x23 | x24 | x25 | x26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | x27 | x28 | FP | LR | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | | | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| | | *
* ------------------------------------------------- *
* | PC | align | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "jump_arm64_aapcs_elf_gas.S"
.text
.align 2
.global jump_fcontext
.type jump_fcontext, %function
jump_fcontext:
# prepare stack for GP + FPU
sub sp, sp, #0xb0
# save d8 - d15
stp d8, d9, [sp, #0x00]
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
# save x19-x30
stp x19, x20, [sp, #0x40]
stp x21, x22, [sp, #0x50]
stp x23, x24, [sp, #0x60]
stp x25, x26, [sp, #0x70]
stp x27, x28, [sp, #0x80]
stp x29, x30, [sp, #0x90]
# save LR as PC
str x30, [sp, #0xa0]
# store RSP (pointing to context-data) in X0
mov x4, sp
# restore RSP (pointing to context-data) from X1
mov sp, x0
# load d8 - d15
ldp d8, d9, [sp, #0x00]
ldp d10, d11, [sp, #0x10]
ldp d12, d13, [sp, #0x20]
ldp d14, d15, [sp, #0x30]
# load x19-x30
ldp x19, x20, [sp, #0x40]
ldp x21, x22, [sp, #0x50]
ldp x23, x24, [sp, #0x60]
ldp x25, x26, [sp, #0x70]
ldp x27, x28, [sp, #0x80]
ldp x29, x30, [sp, #0x90]
# return transfer_t from jump
# pass transfer_t as first arg in context function
# X0 == FCTX, X1 == DATA
mov x0, x4
# load pc
ldr x4, [sp, #0xa0]
# restore stack from GP + FPU
add sp, sp, #0xb0
ret x4
.size jump_fcontext,.-jump_fcontext
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-109
View File
@@ -1,109 +0,0 @@
/*
Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | d8 | d9 | d10 | d11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | d12 | d13 | d14 | d15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | x19 | x20 | x21 | x22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | x23 | x24 | x25 | x26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | x27 | x28 | FP | LR | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | | | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| | | *
* ------------------------------------------------- *
* | PC | align | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.globl _jump_fcontext
.balign 16
_jump_fcontext:
; prepare stack for GP + FPU
sub sp, sp, #0xb0
; save d8 - d15
stp d8, d9, [sp, #0x00]
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
; save x19-x30
stp x19, x20, [sp, #0x40]
stp x21, x22, [sp, #0x50]
stp x23, x24, [sp, #0x60]
stp x25, x26, [sp, #0x70]
stp x27, x28, [sp, #0x80]
stp fp, lr, [sp, #0x90]
; save LR as PC
str lr, [sp, #0xa0]
; store RSP (pointing to context-data) in X0
mov x4, sp
; restore RSP (pointing to context-data) from X1
mov sp, x0
; load d8 - d15
ldp d8, d9, [sp, #0x00]
ldp d10, d11, [sp, #0x10]
ldp d12, d13, [sp, #0x20]
ldp d14, d15, [sp, #0x30]
; load x19-x30
ldp x19, x20, [sp, #0x40]
ldp x21, x22, [sp, #0x50]
ldp x23, x24, [sp, #0x60]
ldp x25, x26, [sp, #0x70]
ldp x27, x28, [sp, #0x80]
ldp fp, lr, [sp, #0x90]
; return transfer_t from jump
; pass transfer_t as first arg in context function
; X0 == FCTX, X1 == DATA
mov x0, x4
; load pc
ldr x4, [sp, #0xa0]
; restore stack from GP + FPU
add sp, sp, #0xb0
ret x4
-88
View File
@@ -1,88 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* |hiddn| v1 | v2 | v3 | v4 | v5 | v6 | v7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | v8 | lr | pc | FCTX| DATA| | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "jump_arm_aapcs_elf_gas.S"
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,%function
.syntax unified
jump_fcontext:
@ save LR as PC
push {lr}
@ save hidden,V1-V8,LR
push {a1,v1-v8,lr}
@ prepare stack for FPU
sub sp, sp, #64
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@ save S16-S31
vstmia sp, {d8-d15}
#endif
@ store RSP (pointing to context-data) in A1
mov a1, sp
@ restore RSP (pointing to context-data) from A2
mov sp, a2
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@ restore S16-S31
vldmia sp, {d8-d15}
#endif
@ prepare stack for FPU
add sp, sp, #64
@ restore hidden,V1-V8,LR
pop {a4,v1-v8,lr}
@ return transfer_t from jump
str a1, [a4, #0]
str a3, [a4, #4]
@ pass transfer_t as first arg in context function
@ A1 == FCTX, A2 == DATA
mov a2, a3
@ restore PC
pop {pc}
.size jump_fcontext,.-jump_fcontext
@ Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-95
View File
@@ -1,95 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | sjlj|hiddn| v1 | v2 | v3 | v4 | v5 | v6 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | v7 | v8 | lr | pc | FCTX| DATA| | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.globl _jump_fcontext
.align 2
_jump_fcontext:
@ save LR as PC
push {lr}
@ save hidden,V1-V8,LR
push {a1,v1-v8,lr}
@ locate TLS to save/restore SjLj handler
mrc p15, 0, v2, c13, c0, #3
bic v2, v2, #3
@ load TLS[__PTK_LIBC_DYLD_Unwind_SjLj_Key]
ldr v1, [v2, #8]
@ save SjLj handler
push {v1}
@ prepare stack for FPU
sub sp, sp, #64
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@ save S16-S31
vstmia sp, {d8-d15}
#endif
@ store RSP (pointing to context-data) in A1
mov a1, sp
@ restore RSP (pointing to context-data) from A2
mov sp, a2
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
@ restore S16-S31
vldmia sp, {d8-d15}
#endif
@ prepare stack for FPU
add sp, sp, #64
@ r#estore SjLj handler
pop {v1}
@ store SjLj handler in TLS
str v1, [v2, #8]
@ restore hidden,V1-V8,LR
pop {a4,v1-v8,lr}
@ return transfer_t from jump
str a1, [a4, #0]
str a3, [a4, #4]
@ pass transfer_t as first arg in context function
@ A1 == FCTX, A2 == DATA
mov a2, a3
@ restore PC
pop {pc}
-24
View File
@@ -1,24 +0,0 @@
/*
Copyright Sergue E. Leontiev 2013.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
// Stub file for universal binary
#if defined(__i386__)
#include "jump_i386_sysv_macho_gas.S"
#elif defined(__x86_64__)
#include "jump_x86_64_sysv_macho_gas.S"
#elif defined(__ppc__)
#include "jump_ppc32_sysv_macho_gas.S"
#elif defined(__ppc64__)
#include "jump_ppc64_sysv_macho_gas.S"
#elif defined(__arm__)
#include "jump_arm_aapcs_macho_gas.S"
#elif defined(__arm64__)
#include "jump_arm64_aapcs_macho_gas.S"
#else
#error "No arch's"
#endif
-116
View File
@@ -1,116 +0,0 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ---------------------------------------------------------------------------------
; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
; ---------------------------------------------------------------------------------
; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch |
; ---------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI |
; ---------------------------------------------------------------------------------
; ---------------------------------------------------------------------------------
; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
; ---------------------------------------------------------------------------------
; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch |
; ---------------------------------------------------------------------------------
; | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR|
; ---------------------------------------------------------------------------------
.386
.XMM
.model flat, c
.code
jump_fcontext PROC BOOST_CONTEXT_EXPORT
; prepare stack
lea esp, [esp-02ch]
IFNDEF BOOST_USE_TSX
; save MMX control- and status-word
stmxcsr [esp]
; save x87 control-word
fnstcw [esp+04h]
ENDIF
assume fs:nothing
; load NT_TIB into ECX
mov edx, fs:[018h]
assume fs:error
; load fiber local storage
mov eax, [edx+010h]
mov [esp+08h], eax
; load current deallocation stack
mov eax, [edx+0e0ch]
mov [esp+0ch], eax
; load current stack limit
mov eax, [edx+08h]
mov [esp+010h], eax
; load current stack base
mov eax, [edx+04h]
mov [esp+014h], eax
; load current SEH exception list
mov eax, [edx]
mov [esp+018h], eax
mov [esp+01ch], edi ; save EDI
mov [esp+020h], esi ; save ESI
mov [esp+024h], ebx ; save EBX
mov [esp+028h], ebp ; save EBP
; store ESP (pointing to context-data) in EAX
mov eax, esp
; firstarg of jump_fcontext() == fcontext to jump to
mov ecx, [esp+030h]
; restore ESP (pointing to context-data) from ECX
mov esp, ecx
IFNDEF BOOST_USE_TSX
; restore MMX control- and status-word
ldmxcsr [esp]
; restore x87 control-word
fldcw [esp+04h]
ENDIF
assume fs:nothing
; load NT_TIB into EDX
mov edx, fs:[018h]
assume fs:error
; restore fiber local storage
mov ecx, [esp+08h]
mov [edx+010h], ecx
; restore current deallocation stack
mov ecx, [esp+0ch]
mov [edx+0e0ch], ecx
; restore current stack limit
mov ecx, [esp+010h]
mov [edx+08h], ecx
; restore current stack base
mov ecx, [esp+014h]
mov [edx+04h], ecx
; restore current SEH exception list
mov ecx, [esp+018h]
mov [edx], ecx
mov ecx, [esp+02ch] ; restore EIP
mov edi, [esp+01ch] ; restore EDI
mov esi, [esp+020h] ; restore ESI
mov ebx, [esp+024h] ; restore EBX
mov ebp, [esp+028h] ; restore EBP
; prepare stack
lea esp, [esp+030h]
; return transfer_t
; FCTX == EAX, DATA == EDX
mov edx, [eax+034h]
; jump to context
jmp ecx
jump_fcontext ENDP
END
-83
View File
@@ -1,83 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* ---------------------------------------------------------------------------------- *
* | to | data | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.file "jump_i386_sysv_elf_gas.S"
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
jump_fcontext:
leal -0x18(%esp), %esp /* prepare stack */
#if !defined(BOOST_USE_TSX)
stmxcsr (%esp) /* save MMX control- and status-word */
fnstcw 0x4(%esp) /* save x87 control-word */
#endif
movl %edi, 0x8(%esp) /* save EDI */
movl %esi, 0xc(%esp) /* save ESI */
movl %ebx, 0x10(%esp) /* save EBX */
movl %ebp, 0x14(%esp) /* save EBP */
/* store ESP (pointing to context-data) in ECX */
movl %esp, %ecx
/* first arg of jump_fcontext() == fcontext to jump to */
movl 0x20(%esp), %eax
/* second arg of jump_fcontext() == data to be transferred */
movl 0x24(%esp), %edx
/* restore ESP (pointing to context-data) from EAX */
movl %eax, %esp
/* address of returned transport_t */
movl 0x1c(%esp), %eax
/* return parent fcontext_t */
movl %ecx, (%eax)
/* return data */
movl %edx, 0x4(%eax)
movl 0x18(%esp), %ecx /* restore EIP */
#if !defined(BOOST_USE_TSX)
ldmxcsr (%esp) /* restore MMX control- and status-word */
fldcw 0x4(%esp) /* restore x87 control-word */
#endif
movl 0x8(%esp), %edi /* restore EDI */
movl 0xc(%esp), %esi /* restore ESI */
movl 0x10(%esp), %ebx /* restore EBX */
movl 0x14(%esp), %ebp /* restore EBP */
leal 0x20(%esp), %esp /* prepare stack */
/* jump to context */
jmp *%ecx
.size jump_fcontext,.-jump_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-74
View File
@@ -1,74 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | to | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | | *
* ---------------------------------------------------------------------------------- *
* | data | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.text
.globl _jump_fcontext
.align 2
_jump_fcontext:
leal -0x18(%esp), %esp /* prepare stack */
#if !defined(BOOST_USE_TSX)
stmxcsr (%esp) /* save MMX control- and status-word */
fnstcw 0x4(%esp) /* save x87 control-word */
#endif
movl %edi, 0x8(%esp) /* save EDI */
movl %esi, 0xc(%esp) /* save ESI */
movl %ebx, 0x10(%esp) /* save EBX */
movl %ebp, 0x14(%esp) /* save EBP */
/* store ESP (pointing to context-data) in ECX */
movl %esp, %ecx
/* first arg of jump_fcontext() == fcontext to jump to */
movl 0x1c(%esp), %eax
/* second arg of jump_fcontext() == data to be transferred */
movl 0x20(%esp), %edx
/* restore ESP (pointing to context-data) from EAX */
movl %eax, %esp
/* return parent fcontext_t */
movl %ecx, %eax
/* returned data is stored in EDX */
movl 0x18(%esp), %ecx /* restore EIP */
#if !defined(BOOST_USE_TSX)
ldmxcsr (%esp) /* restore MMX control- and status-word */
fldcw 0x4(%esp) /* restore x87 control-word */
#endif
movl 0x8(%esp), %edi /* restore EDI */
movl 0xc(%esp), %esi /* restore ESI */
movl 0x10(%esp), %ebx /* restore EBX */
movl 0x14(%esp), %ebp /* restore EBP */
leal 0x1c(%esp), %esp /* prepare stack */
/* jump to context */
jmp *%ecx
-119
View File
@@ -1,119 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* | F20 | F22 | F24 | F26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | F28 | F30 | S0 | S1 | S2 | S3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | S4 | S5 | S6 | S7 | FP |hiddn| RA | PC | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | ABI ARGS | GP | FCTX| DATA| | *
* ------------------------------------------------- *
* *
* *****************************************************/
.file "jump_mips32_o32_elf_gas.S"
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
.ent jump_fcontext
jump_fcontext:
# reserve space on stack
addiu $sp, $sp, -96
sw $s0, 48($sp) # save S0
sw $s1, 52($sp) # save S1
sw $s2, 56($sp) # save S2
sw $s3, 60($sp) # save S3
sw $s4, 64($sp) # save S4
sw $s5, 68($sp) # save S5
sw $s6, 72($sp) # save S6
sw $s7, 76($sp) # save S7
sw $fp, 80($sp) # save FP
sw $a0, 84($sp) # save hidden, address of returned transfer_t
sw $ra, 88($sp) # save RA
sw $ra, 92($sp) # save RA as PC
#if defined(__mips_hard_float)
s.d $f20, ($sp) # save F20
s.d $f22, 8($sp) # save F22
s.d $f24, 16($sp) # save F24
s.d $f26, 24($sp) # save F26
s.d $f28, 32($sp) # save F28
s.d $f30, 40($sp) # save F30
#endif
# store SP (pointing to context-data) in A0
move $a0, $sp
# restore SP (pointing to context-data) from A1
move $sp, $a1
#if defined(__mips_hard_float)
l.d $f20, ($sp) # restore F20
l.d $f22, 8($sp) # restore F22
l.d $f24, 16($sp) # restore F24
l.d $f26, 24($sp) # restore F26
l.d $f28, 32($sp) # restore F28
l.d $f30, 40($sp) # restore F30
#endif
lw $s0, 48($sp) # restore S0
lw $s1, 52($sp) # restore S1
lw $s2, 56($sp) # restore S2
lw $s3, 60($sp) # restore S3
lw $s4, 64($sp) # restore S4
lw $s5, 68($sp) # restore S5
lw $s6, 72($sp) # restore S6
lw $s7, 76($sp) # restore S7
lw $fp, 80($sp) # restore FP
lw $v0, 84($sp) # restore hidden, address of returned transfer_t
lw $ra, 88($sp) # restore RA
# load PC
lw $t9, 92($sp)
# adjust stack
addiu $sp, $sp, 96
# return transfer_t from jump
sw $a0, ($v0) # fctx of transfer_t
sw $a2, 4($v0) # data of transfer_t
# pass transfer_t as first arg in context function
# A0 == fctx, A1 == data
move $a1, $a2
# jump to context
jr $t9
.end jump_fcontext
.size jump_fcontext, .-jump_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-124
View File
@@ -1,124 +0,0 @@
/*
Copyright Jiaxun Yang 2018.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 8 | 16 | 24 | *
* ------------------------------------------------- *
* | F24 | F25 | F26 | F27 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 40 | 48 | 56 | *
* ------------------------------------------------- *
* | F28 | F29 | F30 | F31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 72 | 80 | 88 | *
* ------------------------------------------------- *
* | S0 | S1 | S2 | S3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | S4 | S5 | S6 | S7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | FP | GP | RA | PC | *
* ------------------------------------------------- *
* *
* *****************************************************/
.file "jump_mips64_n64_elf_gas.S"
.text
.globl jump_fcontext
.align 3
.type jump_fcontext,@function
.ent jump_fcontext
jump_fcontext:
# reserve space on stack
daddiu $sp, $sp, -160
sd $s0, 64($sp) # save S0
sd $s1, 72($sp) # save S1
sd $s2, 80($sp) # save S2
sd $s3, 88($sp) # save S3
sd $s4, 96($sp) # save S4
sd $s5, 104($sp) # save S5
sd $s6, 112($sp) # save S6
sd $s7, 120($sp) # save S7
sd $fp, 128($sp) # save FP
sd $ra, 144($sp) # save RA
sd $ra, 152($sp) # save RA as PC
#if defined(__mips_hard_float)
s.d $f24, 0($sp) # save F24
s.d $f25, 8($sp) # save F25
s.d $f26, 16($sp) # save F26
s.d $f27, 24($sp) # save F27
s.d $f28, 32($sp) # save F28
s.d $f29, 40($sp) # save F29
s.d $f30, 48($sp) # save F30
s.d $f31, 56($sp) # save F31
#endif
# store SP (pointing to old context-data) in v0 as return
move $v0, $sp
# get SP (pointing to new context-data) from a0 param
move $sp, $a0
#if defined(__mips_hard_float)
l.d $f24, 0($sp) # restore F24
l.d $f25, 8($sp) # restore F25
l.d $f26, 16($sp) # restore F26
l.d $f27, 24($sp) # restore F27
l.d $f28, 32($sp) # restore F28
l.d $f29, 40($sp) # restore F29
l.d $f30, 48($sp) # restore F30
l.d $f31, 56($sp) # restore F31
#endif
ld $s0, 64($sp) # restore S0
ld $s1, 72($sp) # restore S1
ld $s2, 80($sp) # restore S2
ld $s3, 88($sp) # restore S3
ld $s4, 96($sp) # restore S4
ld $s5, 104($sp) # restore S5
ld $s6, 112($sp) # restore S6
ld $s7, 120($sp) # restore S7
ld $fp, 128($sp) # restore FP
ld $ra, 144($sp) # restore RAa
# load PC
ld $t9, 152($sp)
# adjust stack
daddiu $sp, $sp, 160
move $a0, $v0 # move old sp from v0 to a0 as param
move $v1, $a1 # move *data from a1 to v1 as return
# jump to context
jr $t9
.end jump_fcontext
.size jump_fcontext, .-jump_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-201
View File
@@ -1,201 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* |bchai|hiddn| fpscr | PC | CR | R14 | R15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | F14 | F15 | F16 | F17 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F18 | F19 | F20 | F21 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | F22 | F23 | F24 | F25 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | F26 | F27 | F28 | F29 | *
* ------------------------------------------------- *
* ------------------------|------------ *
* | 224 | 228 | 232 | 236 | 240 | 244 | *
* ------------------------|------------ *
* | F30 | F31 |bchai| LR | *
* ------------------------|------------ *
* *
*******************************************************/
.file "jump_ppc32_sysv_elf_gas.S"
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
jump_fcontext:
# Linux: jump_fcontext( hidden transfer_t * R3, R4, R5)
# Other: transfer_t R3:R4 = jump_fcontext( R3, R4)
mflr %r0 # return address from LR
mffs %f0 # FPSCR
mfcr %r8 # condition register
stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0
stw %r0, 244(%r1) # save LR in caller's frame
#ifdef __linux__
stw %r3, 4(%r1) # hidden pointer
#endif
stfd %f0, 8(%r1) # FPSCR
stw %r0, 16(%r1) # LR as PC
stw %r8, 20(%r1) # CR
# Save registers R14 to R31.
# Don't change R2, the thread-local storage pointer.
# Don't change R13, the small data pointer.
stw %r14, 24(%r1)
stw %r15, 28(%r1)
stw %r16, 32(%r1)
stw %r17, 36(%r1)
stw %r18, 40(%r1)
stw %r19, 44(%r1)
stw %r20, 48(%r1)
stw %r21, 52(%r1)
stw %r22, 56(%r1)
stw %r23, 60(%r1)
stw %r24, 64(%r1)
stw %r25, 68(%r1)
stw %r26, 72(%r1)
stw %r27, 76(%r1)
stw %r28, 80(%r1)
stw %r29, 84(%r1)
stw %r30, 88(%r1)
stw %r31, 92(%r1)
# Save registers F14 to F31 in slots with 8-byte alignment.
# 4-byte alignment may stall the pipeline of some processors.
# Less than 4 may cause alignment traps.
stfd %f14, 96(%r1)
stfd %f15, 104(%r1)
stfd %f16, 112(%r1)
stfd %f17, 120(%r1)
stfd %f18, 128(%r1)
stfd %f19, 136(%r1)
stfd %f20, 144(%r1)
stfd %f21, 152(%r1)
stfd %f22, 160(%r1)
stfd %f23, 168(%r1)
stfd %f24, 176(%r1)
stfd %f25, 184(%r1)
stfd %f26, 192(%r1)
stfd %f27, 200(%r1)
stfd %f28, 208(%r1)
stfd %f29, 216(%r1)
stfd %f30, 224(%r1)
stfd %f31, 232(%r1)
# store RSP (pointing to context-data) in R7/R6
# restore RSP (pointing to context-data) from R4/R3
#ifdef __linux__
mr %r7, %r1
mr %r1, %r4
lwz %r3, 4(%r1) # hidden pointer
#else
mr %r6, %r1
mr %r1, %r3
#endif
lfd %f0, 8(%r1) # FPSCR
lwz %r0, 16(%r1) # PC
lwz %r8, 20(%r1) # CR
mtfsf 0xff, %f0 # restore FPSCR
mtctr %r0 # load CTR with PC
mtcr %r8 # restore CR
# restore R14 to R31
lwz %r14, 24(%r1)
lwz %r15, 28(%r1)
lwz %r16, 32(%r1)
lwz %r17, 36(%r1)
lwz %r18, 40(%r1)
lwz %r19, 44(%r1)
lwz %r20, 48(%r1)
lwz %r21, 52(%r1)
lwz %r22, 56(%r1)
lwz %r23, 60(%r1)
lwz %r24, 64(%r1)
lwz %r25, 68(%r1)
lwz %r26, 72(%r1)
lwz %r27, 76(%r1)
lwz %r28, 80(%r1)
lwz %r29, 84(%r1)
lwz %r30, 88(%r1)
lwz %r31, 92(%r1)
# restore F14 to F31
lfd %f14, 96(%r1)
lfd %f15, 104(%r1)
lfd %f16, 112(%r1)
lfd %f17, 120(%r1)
lfd %f18, 128(%r1)
lfd %f19, 136(%r1)
lfd %f20, 144(%r1)
lfd %f21, 152(%r1)
lfd %f22, 160(%r1)
lfd %f23, 168(%r1)
lfd %f24, 176(%r1)
lfd %f25, 184(%r1)
lfd %f26, 192(%r1)
lfd %f27, 200(%r1)
lfd %f28, 208(%r1)
lfd %f29, 216(%r1)
lfd %f30, 224(%r1)
lfd %f31, 232(%r1)
# restore LR from caller's frame
lwz %r0, 244(%r1)
mtlr %r0
# adjust stack
addi %r1, %r1, 240
# return transfer_t
#ifdef __linux__
stw %r7, 0(%r3)
stw %r5, 4(%r3)
#else
mr %r3, %r6
# %r4, %r4
#endif
# jump to context
bctr
.size jump_fcontext, .-jump_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-201
View File
@@ -1,201 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* | F14 | F15 | F16 | F17 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | F18 | F19 | F20 | F21 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | F22 | F23 | F24 | F25 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | F26 | F27 | F28 | F29 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F30 | F31 | fpscr | R13 | R14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | | *
* ------------------------------------------------- *
* | 256 | | *
* ------------------------------------------------- *
* | DATA| | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.globl _jump_fcontext
.align 2
_jump_fcontext:
; reserve space on stack
subi r1, r1, 244
stfd f14, 0(r1) # save F14
stfd f15, 8(r1) # save F15
stfd f16, 16(r1) # save F16
stfd f17, 24(r1) # save F17
stfd f18, 32(r1) # save F18
stfd f19, 40(r1) # save F19
stfd f20, 48(r1) # save F20
stfd f21, 56(r1) # save F21
stfd f22, 64(r1) # save F22
stfd f23, 72(r1) # save F23
stfd f24, 80(r1) # save F24
stfd f25, 88(r1) # save F25
stfd f26, 96(r1) # save F26
stfd f27, 104(r1) # save F27
stfd f28, 112(r1) # save F28
stfd f29, 120(r1) # save F29
stfd f30, 128(r1) # save F30
stfd f31, 136(r1) # save F31
mffs f0 # load FPSCR
stfd f0, 144(r1) # save FPSCR
stw r13, 152(r1) # save R13
stw r14, 156(r1) # save R14
stw r15, 160(r1) # save R15
stw r16, 164(r1) # save R16
stw r17, 168(r1) # save R17
stw r18, 172(r1) # save R18
stw r19, 176(r1) # save R19
stw r20, 180(r1) # save R20
stw r21, 184(r1) # save R21
stw r22, 188(r1) # save R22
stw r23, 192(r1) # save R23
stw r24, 196(r1) # save R24
stw r25, 200(r1) # save R25
stw r26, 204(r1) # save R26
stw r27, 208(r1) # save R27
stw r28, 212(r1) # save R28
stw r29, 216(r1) # save R29
stw r30, 220(r1) # save R30
stw r31, 224(r1) # save R31
stw r3, 228(r1) # save hidden
# save CR
mfcr r0
stw r0, 232(r1)
# save LR
mflr r0
stw r0, 236(r1)
# save LR as PC
stw r0, 240(r1)
# store RSP (pointing to context-data) in R6
mr r6, r1
# restore RSP (pointing to context-data) from R4
mr r1, r4
lfd f14, 0(r1) # restore F14
lfd f15, 8(r1) # restore F15
lfd f16, 16(r1) # restore F16
lfd f17, 24(r1) # restore F17
lfd f18, 32(r1) # restore F18
lfd f19, 40(r1) # restore F19
lfd f20, 48(r1) # restore F20
lfd f21, 56(r1) # restore F21
lfd f22, 64(r1) # restore F22
lfd f23, 72(r1) # restore F23
lfd f24, 80(r1) # restore F24
lfd f25, 88(r1) # restore F25
lfd f26, 96(r1) # restore F26
lfd f27, 104(r1) # restore F27
lfd f28, 112(r1) # restore F28
lfd f29, 120(r1) # restore F29
lfd f30, 128(r1) # restore F30
lfd f31, 136(r1) # restore F31
lfd f0, 144(r1) # load FPSCR
mtfsf 0xff, f0 # restore FPSCR
lwz r13, 152(r1) # restore R13
lwz r14, 156(r1) # restore R14
lwz r15, 160(r1) # restore R15
lwz r16, 164(r1) # restore R16
lwz r17, 168(r1) # restore R17
lwz r18, 172(r1) # restore R18
lwz r19, 176(r1) # restore R19
lwz r20, 180(r1) # restore R20
lwz r21, 184(r1) # restore R21
lwz r22, 188(r1) # restore R22
lwz r23, 192(r1) # restore R23
lwz r24, 196(r1) # restore R24
lwz r25, 200(r1) # restore R25
lwz r26, 204(r1) # restore R26
lwz r27, 208(r1) # restore R27
lwz r28, 212(r1) # restore R28
lwz r29, 216(r1) # restore R29
lwz r30, 220(r1) # restore R30
lwz r31, 224(r1) # restore R31
lwz r3, 228(r1) # restore hidden
# restore CR
lwz r0, 232(r1)
mtcr r0
# restore LR
lwz r0, 236(r1)
mtlr r0
# load PC
lwz r0, 240(r1)
# restore CTR
mtctr r0
# adjust stack
addi r1, r1, 244
# return transfer_t
stw r6, 0(r3)
stw r5, 4(r3)
# jump to context
bctr
-221
View File
@@ -1,221 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* | TOC | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | TOC saved | FCTX | DATA | | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "jump_ppc64_sysv_elf_gas.S"
.globl jump_fcontext
#if _CALL_ELF == 2
.text
.align 2
jump_fcontext:
addis %r2, %r12, .TOC.-jump_fcontext@ha
addi %r2, %r2, .TOC.-jump_fcontext@l
.localentry jump_fcontext, . - jump_fcontext
#else
.section ".opd","aw"
.align 3
jump_fcontext:
# ifdef _CALL_LINUX
.quad .L.jump_fcontext,.TOC.@tocbase,0
.type jump_fcontext,@function
.text
.align 2
.L.jump_fcontext:
# else
.hidden .jump_fcontext
.globl .jump_fcontext
.quad .jump_fcontext,.TOC.@tocbase,0
.size jump_fcontext,24
.type .jump_fcontext,@function
.text
.align 2
.jump_fcontext:
# endif
#endif
# reserve space on stack
subi %r1, %r1, 184
#if _CALL_ELF != 2
std %r2, 0(%r1) # save TOC
#endif
std %r14, 8(%r1) # save R14
std %r15, 16(%r1) # save R15
std %r16, 24(%r1) # save R16
std %r17, 32(%r1) # save R17
std %r18, 40(%r1) # save R18
std %r19, 48(%r1) # save R19
std %r20, 56(%r1) # save R20
std %r21, 64(%r1) # save R21
std %r22, 72(%r1) # save R22
std %r23, 80(%r1) # save R23
std %r24, 88(%r1) # save R24
std %r25, 96(%r1) # save R25
std %r26, 104(%r1) # save R26
std %r27, 112(%r1) # save R27
std %r28, 120(%r1) # save R28
std %r29, 128(%r1) # save R29
std %r30, 136(%r1) # save R30
std %r31, 144(%r1) # save R31
#if _CALL_ELF != 2
std %r3, 152(%r1) # save hidden
#endif
# save CR
mfcr %r0
std %r0, 160(%r1)
# save LR
mflr %r0
std %r0, 168(%r1)
# save LR as PC
std %r0, 176(%r1)
# store RSP (pointing to context-data) in R6
mr %r6, %r1
#if _CALL_ELF == 2
# restore RSP (pointing to context-data) from R3
mr %r1, %r3
#else
# restore RSP (pointing to context-data) from R4
mr %r1, %r4
ld %r2, 0(%r1) # restore TOC
#endif
ld %r14, 8(%r1) # restore R14
ld %r15, 16(%r1) # restore R15
ld %r16, 24(%r1) # restore R16
ld %r17, 32(%r1) # restore R17
ld %r18, 40(%r1) # restore R18
ld %r19, 48(%r1) # restore R19
ld %r20, 56(%r1) # restore R20
ld %r21, 64(%r1) # restore R21
ld %r22, 72(%r1) # restore R22
ld %r23, 80(%r1) # restore R23
ld %r24, 88(%r1) # restore R24
ld %r25, 96(%r1) # restore R25
ld %r26, 104(%r1) # restore R26
ld %r27, 112(%r1) # restore R27
ld %r28, 120(%r1) # restore R28
ld %r29, 128(%r1) # restore R29
ld %r30, 136(%r1) # restore R30
ld %r31, 144(%r1) # restore R31
#if _CALL_ELF != 2
ld %r3, 152(%r1) # restore hidden
#endif
# restore CR
ld %r0, 160(%r1)
mtcr %r0
# restore LR
ld %r0, 168(%r1)
mtlr %r0
# load PC
ld %r12, 176(%r1)
# restore CTR
mtctr %r12
# adjust stack
addi %r1, %r1, 184
#if _CALL_ELF == 2
# copy transfer_t into transfer_fn arg registers
mr %r3, %r6
# arg pointer already in %r4
# jump to context
bctr
.size jump_fcontext, .-jump_fcontext
#else
# zero in r3 indicates first jump to context-function
cmpdi %r3, 0
beq use_entry_arg
# return transfer_t
std %r6, 0(%r3)
std %r5, 8(%r3)
# jump to context
bctr
use_entry_arg:
# copy transfer_t into transfer_fn arg registers
mr %r3, %r6
mr %r4, %r5
# jump to context
bctr
# ifdef _CALL_LINUX
.size .jump_fcontext, .-.L.jump_fcontext
# else
.size .jump_fcontext, .-.jump_fcontext
# endif
#endif
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-164
View File
@@ -1,164 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* | TOC | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | TOC saved | FCTX | DATA | | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.align 2
.globl _jump_fcontext
_jump_fcontext:
; reserve space on stack
subi r1, r1, 184
std r14, 8(r1) ; save R14
std r15, 16(r1) ; save R15
std r16, 24(r1) ; save R16
std r17, 32(r1) ; save R17
std r18, 40(r1) ; save R18
std r19, 48(r1) ; save R19
std r20, 56(r1) ; save R20
std r21, 64(r1) ; save R21
std r22, 72(r1) ; save R22
std r23, 80(r1) ; save R23
std r24, 88(r1) ; save R24
std r25, 96(r1) ; save R25
std r26, 104(r1) ; save R26
std r27, 112(r1) ; save R27
std r28, 120(r1) ; save R28
std r29, 128(r1) ; save R29
std r30, 136(r1) ; save R30
std r31, 144(r1) ; save R31
std r3, 152(r1) ; save hidden
; save CR
mfcr r0
std r0, 160(r1)
; save LR
mflr r0
std r0, 168(r1)
; save LR as PC
std r0, 176(r1)
; store RSP (pointing to context-data) in R6
mr r6, r1
; restore RSP (pointing to context-data) from R4
mr r1, r4
ld r14, 8(r1) ; restore R14
ld r15, 16(r1) ; restore R15
ld r16, 24(r1) ; restore R16
ld r17, 32(r1) ; restore R17
ld r18, 40(r1) ; restore R18
ld r19, 48(r1) ; restore R19
ld r20, 56(r1) ; restore R20
ld r21, 64(r1) ; restore R21
ld r22, 72(r1) ; restore R22
ld r23, 80(r1) ; restore R23
ld r24, 88(r1) ; restore R24
ld r25, 96(r1) ; restore R25
ld r26, 104(r1) ; restore R26
ld r27, 112(r1) ; restore R27
ld r28, 120(r1) ; restore R28
ld r29, 128(r1) ; restore R29
ld r30, 136(r1) ; restore R30
ld r31, 144(r1) ; restore R31
ld r3, 152(r1) ; restore hidden
; restore CR
ld r0, 160(r1)
mtcr r0
; restore LR
ld r0, 168(r1)
mtlr r0
; load PC
ld r12, 176(r1)
# restore CTR
mtctr r12
# adjust stack
addi r1, r1, 184
# zero in r3 indicates first jump to context-function
cmpdi r3, 0
beq use_entry_arg
# return transfer_t
std r6, 0(r3)
std r5, 8(r3)
# jump to context
bctr
use_entry_arg:
# copy transfer_t into transfer_fn arg registers
mr r3, r6
mr r4, r5
# jump to context
bctr
-156
View File
@@ -1,156 +0,0 @@
/*******************************************************
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 8 | 16 | 24 | *
* ------------------------------------------------- *
* | t.fctx | t.data | r2 | r6 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 40 | 48 | 56 | *
* ------------------------------------------------- *
* | r7 | r8 | r9 | r10 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 72 | 80 | 88 | *
* ------------------------------------------------- *
* | r11 | r12 | r13 | r14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 104 | 112 | 120 | *
* ------------------------------------------------- *
* | f8 | f9 | f10 | f11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 136 | 144 | 152 | *
* ------------------------------------------------- *
* | f12 | f13 | f14 | f15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 168 | 176 | | *
* ------------------------------------------------- *
* | fpc | pc | | | *
* ------------------------------------------------- *
*******************************************************/
.text
.align 8
.global jump_fcontext
.type jump_fcontext, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
#define FP_OFFSET 96
#define FPC_OFFSET 160
#define PC_OFFSET 168
#define CONTEXT_SIZE 176
#define REG_SAVE_AREA_SIZE 160
/*
typedef void* fcontext_t;
struct transfer_t {
fcontext_t fctx;
void * data;
};
transfer_t jump_fcontext( fcontext_t const to,
void * data);
Incoming args
r2 - Hidden argument to the location where the return transfer_t needs to be returned
r3 - Context we want to switch to
r4 - Data pointer
*/
jump_fcontext:
.machine "z10"
/* Reserve stack space to store the current context. */
aghi %r15,-CONTEXT_SIZE
/* Save the argument register holding the location of the return value. */
stg %r2,GR_OFFSET(%r15)
/* Save the call-saved general purpose registers. */
stmg %r6,%r14,GR_OFFSET+8(%r15)
/* Save call-saved floating point registers. */
std %f8,FP_OFFSET(%r15)
std %f9,FP_OFFSET+8(%r15)
std %f10,FP_OFFSET+16(%r15)
std %f11,FP_OFFSET+24(%r15)
std %f12,FP_OFFSET+32(%r15)
std %f13,FP_OFFSET+40(%r15)
std %f14,FP_OFFSET+48(%r15)
std %f15,FP_OFFSET+56(%r15)
/* Save the return address as current pc. */
stg %r14,PC_OFFSET(%r15)
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r15)
/* Backup the stack pointer pointing to the old context-data into r1. */
lgr %r1,%r15
/* Load the new context pointer as stack pointer. */
lgr %r15,%r3
/* Restore the call-saved GPRs from the new context. */
lmg %r6,%r14,GR_OFFSET+8(%r15)
/* Restore call-saved floating point registers. */
ld %f8,FP_OFFSET(%r15)
ld %f9,FP_OFFSET+8(%r15)
ld %f10,FP_OFFSET+16(%r15)
ld %f11,FP_OFFSET+24(%r15)
ld %f12,FP_OFFSET+32(%r15)
ld %f13,FP_OFFSET+40(%r15)
ld %f14,FP_OFFSET+48(%r15)
ld %f15,FP_OFFSET+56(%r15)
/* Load the floating point control register. */
lfpc FPC_OFFSET(%r15)
/* Restore PC - the location where we will jump to at the end. */
lg %r5,PC_OFFSET(%r15)
ltg %r2,GR_OFFSET(%r15)
jnz use_return_slot
/* We restore a make_fcontext context. Use the function
argument slot in the context we just saved and allocate the
register save area for the target function. */
la %r2,ARG_OFFSET(%r1)
aghi %r15,-REG_SAVE_AREA_SIZE
use_return_slot:
/* Save the two fields in transfer_t. When calling a
make_fcontext function this becomes the function argument of
the target function, otherwise it will be the return value of
jump_fcontext. */
stg %r1,0(%r2)
stg %r4,8(%r2)
/* Free the restored context. */
aghi %r15,CONTEXT_SIZE
/* Jump to the PC loaded from the new context. */
br %r5
.size jump_fcontext,.-jump_fcontext
.section .note.GNU-stack,"",%progbits
-205
View File
@@ -1,205 +0,0 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ----------------------------------------------------------------------------------
; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
; ----------------------------------------------------------------------------------
; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
; ----------------------------------------------------------------------------------
; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
; ----------------------------------------------------------------------------------
; | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
; ----------------------------------------------------------------------------------
; | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
; ----------------------------------------------------------------------------------
; | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c |
; ----------------------------------------------------------------------------------
; | SEE registers (XMM6-XMM15) |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
; ----------------------------------------------------------------------------------
; | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc |
; ----------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| <alignment> | fbr_strg | fc_dealloc |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
; ----------------------------------------------------------------------------------
; | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc |
; ----------------------------------------------------------------------------------
; | limit | base | R12 | R13 |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
; ----------------------------------------------------------------------------------
; | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc |
; ----------------------------------------------------------------------------------
; | R14 | R15 | RDI | RSI |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
; ----------------------------------------------------------------------------------
; | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c |
; ----------------------------------------------------------------------------------
; | RBX | RBP | hidden | RIP |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
; ----------------------------------------------------------------------------------
; | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c |
; ----------------------------------------------------------------------------------
; | parameter area |
; ----------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------
; | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
; ----------------------------------------------------------------------------------
; | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c |
; ----------------------------------------------------------------------------------
; | FCTX | DATA | |
; ----------------------------------------------------------------------------------
.code
jump_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
.endprolog
; prepare stack
lea rsp, [rsp-0118h]
IFNDEF BOOST_USE_TSX
; save XMM storage
movaps [rsp], xmm6
movaps [rsp+010h], xmm7
movaps [rsp+020h], xmm8
movaps [rsp+030h], xmm9
movaps [rsp+040h], xmm10
movaps [rsp+050h], xmm11
movaps [rsp+060h], xmm12
movaps [rsp+070h], xmm13
movaps [rsp+080h], xmm14
movaps [rsp+090h], xmm15
; save MMX control- and status-word
stmxcsr [rsp+0a0h]
; save x87 control-word
fnstcw [rsp+0a4h]
ENDIF
; load NT_TIB
mov r10, gs:[030h]
; save fiber local storage
mov rax, [r10+020h]
mov [rsp+0b0h], rax
; save current deallocation stack
mov rax, [r10+01478h]
mov [rsp+0b8h], rax
; save current stack limit
mov rax, [r10+010h]
mov [rsp+0c0h], rax
; save current stack base
mov rax, [r10+08h]
mov [rsp+0c8h], rax
mov [rsp+0d0h], r12 ; save R12
mov [rsp+0d8h], r13 ; save R13
mov [rsp+0e0h], r14 ; save R14
mov [rsp+0e8h], r15 ; save R15
mov [rsp+0f0h], rdi ; save RDI
mov [rsp+0f8h], rsi ; save RSI
mov [rsp+0100h], rbx ; save RBX
mov [rsp+0108h], rbp ; save RBP
mov [rsp+0110h], rcx ; save hidden address of transport_t
; preserve RSP (pointing to context-data) in R9
mov r9, rsp
; restore RSP (pointing to context-data) from RDX
mov rsp, rdx
IFNDEF BOOST_USE_TSX
; restore XMM storage
movaps xmm6, [rsp]
movaps xmm7, [rsp+010h]
movaps xmm8, [rsp+020h]
movaps xmm9, [rsp+030h]
movaps xmm10, [rsp+040h]
movaps xmm11, [rsp+050h]
movaps xmm12, [rsp+060h]
movaps xmm13, [rsp+070h]
movaps xmm14, [rsp+080h]
movaps xmm15, [rsp+090h]
; restore MMX control- and status-word
ldmxcsr [rsp+0a0h]
; save x87 control-word
fldcw [rsp+0a4h]
ENDIF
; load NT_TIB
mov r10, gs:[030h]
; restore fiber local storage
mov rax, [rsp+0b0h]
mov [r10+020h], rax
; restore current deallocation stack
mov rax, [rsp+0b8h]
mov [r10+01478h], rax
; restore current stack limit
mov rax, [rsp+0c0h]
mov [r10+010h], rax
; restore current stack base
mov rax, [rsp+0c8h]
mov [r10+08h], rax
mov r12, [rsp+0d0h] ; restore R12
mov r13, [rsp+0d8h] ; restore R13
mov r14, [rsp+0e0h] ; restore R14
mov r15, [rsp+0e8h] ; restore R15
mov rdi, [rsp+0f0h] ; restore RDI
mov rsi, [rsp+0f8h] ; restore RSI
mov rbx, [rsp+0100h] ; restore RBX
mov rbp, [rsp+0108h] ; restore RBP
mov rax, [rsp+0110h] ; restore hidden address of transport_t
; prepare stack
lea rsp, [rsp+0118h]
; load return-address
pop r10
; transport_t returned in RAX
; return parent fcontext_t
mov [rax], r9
; return data
mov [rax+08h], r8
; transport_t as 1.arg of context-function
mov rcx, rax
; indirect jump to context
jmp r10
jump_fcontext ENDP
END
-91
View File
@@ -1,91 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBX | RBP | RIP | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.file "jump_x86_64_sysv_elf_gas.S"
.text
.globl jump_fcontext
.type jump_fcontext,@function
.align 16
jump_fcontext:
leaq -0x38(%rsp), %rsp /* prepare stack */
#if !defined(BOOST_USE_TSX)
stmxcsr (%rsp) /* save MMX control- and status-word */
fnstcw 0x4(%rsp) /* save x87 control-word */
#endif
movq %r12, 0x8(%rsp) /* save R12 */
movq %r13, 0x10(%rsp) /* save R13 */
movq %r14, 0x18(%rsp) /* save R14 */
movq %r15, 0x20(%rsp) /* save R15 */
movq %rbx, 0x28(%rsp) /* save RBX */
movq %rbp, 0x30(%rsp) /* save RBP */
/* store RSP (pointing to context-data) in RAX */
movq %rsp, %rax
/* restore RSP (pointing to context-data) from RDI */
movq %rdi, %rsp
movq 0x38(%rsp), %r8 /* restore return-address */
#if !defined(BOOST_USE_TSX)
ldmxcsr (%rsp) /* restore MMX control- and status-word */
fldcw 0x4(%rsp) /* restore x87 control-word */
#endif
movq 0x8(%rsp), %r12 /* restore R12 */
movq 0x10(%rsp), %r13 /* restore R13 */
movq 0x18(%rsp), %r14 /* restore R14 */
movq 0x20(%rsp), %r15 /* restore R15 */
movq 0x28(%rsp), %rbx /* restore RBX */
movq 0x30(%rsp), %rbp /* restore RBP */
leaq 0x40(%rsp), %rsp /* prepare stack */
/* return transfer_t from jump */
#if !defined(_ILP32)
/* RAX == fctx, RDX == data */
movq %rsi, %rdx
#else
/* RAX == data:fctx */
salq $32, %rsi
orq %rsi, %rax
#endif
/* pass transfer_t as first arg in context function */
#if !defined(_ILP32)
/* RDI == fctx, RSI == data */
#else
/* RDI == data:fctx */
#endif
movq %rax, %rdi
/* indirect jump to context */
jmp *%r8
.size jump_fcontext,.-jump_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-75
View File
@@ -1,75 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBX | RBP | RIP | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.text
.globl _jump_fcontext
.align 8
_jump_fcontext:
leaq -0x38(%rsp), %rsp /* prepare stack */
#if !defined(BOOST_USE_TSX)
stmxcsr (%rsp) /* save MMX control- and status-word */
fnstcw 0x4(%rsp) /* save x87 control-word */
#endif
movq %r12, 0x8(%rsp) /* save R12 */
movq %r13, 0x10(%rsp) /* save R13 */
movq %r14, 0x18(%rsp) /* save R14 */
movq %r15, 0x20(%rsp) /* save R15 */
movq %rbx, 0x28(%rsp) /* save RBX */
movq %rbp, 0x30(%rsp) /* save RBP */
/* store RSP (pointing to context-data) in RAX */
movq %rsp, %rax
/* restore RSP (pointing to context-data) from RDI */
movq %rdi, %rsp
movq 0x38(%rsp), %r8 /* restore return-address */
#if !defined(BOOST_USE_TSX)
ldmxcsr (%rsp) /* restore MMX control- and status-word */
fldcw 0x4(%rsp) /* restore x87 control-word */
#endif
movq 0x8(%rsp), %r12 /* restore R12 */
movq 0x10(%rsp), %r13 /* restore R13 */
movq 0x18(%rsp), %r14 /* restore R14 */
movq 0x20(%rsp), %r15 /* restore R15 */
movq 0x28(%rsp), %rbx /* restore RBX */
movq 0x30(%rsp), %rbp /* restore RBP */
leaq 0x40(%rsp), %rsp /* prepare stack */
/* return transfer_t from jump */
/* RAX == fctx, RDX == data */
movq %rsi, %rdx
/* pass transfer_t as first arg in context function */
/* RDI == fctx, RSI == data */
movq %rax, %rdi
/* indirect jump to context */
jmp *%r8
-85
View File
@@ -1,85 +0,0 @@
/*
Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | d8 | d9 | d10 | d11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | d12 | d13 | d14 | d15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | x19 | x20 | x21 | x22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | x23 | x24 | x25 | x26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | x27 | x28 | FP | LR | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | | | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| | | *
* ------------------------------------------------- *
* | PC | align | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "make_arm64_aapcs_elf_gas.S"
.text
.align 2
.global make_fcontext
.type make_fcontext, %function
make_fcontext:
# shift address in x0 (allocated stack) to lower 16 byte boundary
and x0, x0, ~0xF
# reserve space for context-data on context-stack
sub x0, x0, #0xb0
# third arg of make_fcontext() == address of context-function
# store address as a PC to jump in
str x2, [x0, #0xa0]
# save address of finish as return-address for context-function
# will be entered after context-function returns (LR register)
adr x1, finish
str x1, [x0, #0x98]
ret x30 // return pointer to context-data (x0)
finish:
# exit code is zero
mov x0, #0
# exit application
bl _exit
.size make_fcontext,.-make_fcontext
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-83
View File
@@ -1,83 +0,0 @@
/*
Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | d8 | d9 | d10 | d11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | d12 | d13 | d14 | d15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | x19 | x20 | x21 | x22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | x23 | x24 | x25 | x26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | x27 | x28 | FP | LR | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | | | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| | | *
* ------------------------------------------------- *
* | PC | align | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.globl _make_fcontext
.balign 16
_make_fcontext:
; shift address in x0 (allocated stack) to lower 16 byte boundary
and x0, x0, ~0xF
; reserve space for context-data on context-stack
sub x0, x0, #0xb0
; third arg of make_fcontext() == address of context-function
; store address as a PC to jump in
str x2, [x0, #0xa0]
adr x1, finish
; save address of finish as return-address for context-function
; will be entered after context-function returns (LR register)
str x1, [x0, #0x98]
ret lr ; return pointer to context-data (x0)
finish:
; exit code is zero
mov x0, #0
; exit application
bl __exit
-81
View File
@@ -1,81 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* |hiddn| v1 | v2 | v3 | v4 | v5 | v6 | v7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | v8 | lr | pc | FCTX| DATA| | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "make_arm_aapcs_elf_gas.S"
.text
.globl make_fcontext
.align 2
.type make_fcontext,%function
.syntax unified
make_fcontext:
@ shift address in A1 to lower 16 byte boundary
bic a1, a1, #15
@ reserve space for context-data on context-stack
sub a1, a1, #124
@ third arg of make_fcontext() == address of context-function
str a3, [a1, #104]
@ compute address of returned transfer_t
add a2, a1, #108
mov a3, a2
str a3, [a1, #64]
@ compute abs address of label finish
adr a2, finish
@ save address of finish as return-address for context-function
@ will be entered after context-function returns
str a2, [a1, #100]
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
#endif
bx lr @ return pointer to context-data
finish:
@ exit code is zero
mov a1, #0
@ exit application
bl _exit@PLT
.size make_fcontext,.-make_fcontext
@ Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-71
View File
@@ -1,71 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | sjlj|hiddn| v1 | v2 | v3 | v4 | v5 | v6 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | v7 | v8 | lr | pc | FCTX| DATA| | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.globl _make_fcontext
.align 2
_make_fcontext:
@ shift address in A1 to lower 16 byte boundary
bic a1, a1, #15
@ reserve space for context-data on context-stack
sub a1, a1, #124
@ third arg of make_fcontext() == address of context-function
str a3, [a1, #108]
@ compute address of returned transfer_t
add a2, a1, #112
mov a3, a2
str a3, [a1, #68]
@ compute abs address of label finish
adr a2, finish
@ save address of finish as return-address for context-function
@ will be entered after context-function returns
str a2, [a1, #104]
bx lr @ return pointer to context-data
finish:
@ exit code is zero
mov a1, #0
@ exit application
bl __exit
-24
View File
@@ -1,24 +0,0 @@
/*
Copyright Sergue E. Leontiev 2013.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
// Stub file for universal binary
#if defined(__i386__)
#include "make_i386_sysv_macho_gas.S"
#elif defined(__x86_64__)
#include "make_x86_64_sysv_macho_gas.S"
#elif defined(__ppc__)
#include "make_ppc32_sysv_macho_gas.S"
#elif defined(__ppc64__)
#include "make_ppc64_sysv_macho_gas.S"
#elif defined(__arm__)
#include "make_arm_aapcs_macho_gas.S"
#elif defined(__arm64__)
#include "make_arm64_aapcs_macho_gas.S"
#else
#error "No arch's"
#endif
-140
View File
@@ -1,140 +0,0 @@
; Copyright Oliver Kowalke 2009.
; Distributed under the Boost Software License, Version 1.0.
; (See accompanying file LICENSE_1_0.txt or copy at
; http://www.boost.org/LICENSE_1_0.txt)
; ---------------------------------------------------------------------------------
; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
; ---------------------------------------------------------------------------------
; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch |
; ---------------------------------------------------------------------------------
; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI |
; ---------------------------------------------------------------------------------
; ---------------------------------------------------------------------------------
; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
; ---------------------------------------------------------------------------------
; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch |
; ---------------------------------------------------------------------------------
; | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR|
; ---------------------------------------------------------------------------------
.386
.XMM
.model flat, c
; standard C library function
_exit PROTO, value:SDWORD
.code
make_fcontext PROC BOOST_CONTEXT_EXPORT
; first arg of make_fcontext() == top of context-stack
mov eax, [esp+04h]
; reserve space for first argument of context-function
; EAX might already point to a 16byte border
lea eax, [eax-08h]
; shift address in EAX to lower 16 byte boundary
and eax, -16
; reserve space for context-data on context-stack
; on context-function entry: (ESP -0x4) % 8 == 0
; additional space is required for SEH
lea eax, [eax-040h]
; save MMX control- and status-word
stmxcsr [eax]
; save x87 control-word
fnstcw [eax+04h]
; first arg of make_fcontext() == top of context-stack
mov ecx, [esp+04h]
; save top address of context stack as 'base'
mov [eax+014h], ecx
; second arg of make_fcontext() == size of context-stack
mov edx, [esp+08h]
; negate stack size for LEA instruction (== substraction)
neg edx
; compute bottom address of context stack (limit)
lea ecx, [ecx+edx]
; save bottom address of context-stack as 'limit'
mov [eax+010h], ecx
; save bottom address of context-stack as 'dealloction stack'
mov [eax+0ch], ecx
; set fiber-storage to zero
xor ecx, ecx
mov [eax+08h], ecx
; third arg of make_fcontext() == address of context-function
; stored in EBX
mov ecx, [esp+0ch]
mov [eax+024h], ecx
; compute abs address of label trampoline
mov ecx, trampoline
; save address of trampoline as return-address for context-function
; will be entered after calling jump_fcontext() first time
mov [eax+02ch], ecx
; compute abs address of label finish
mov ecx, finish
; save address of finish as return-address for context-function in EBP
; will be entered after context-function returns
mov [eax+028h], ecx
; traverse current seh chain to get the last exception handler installed by Windows
; note that on Windows Server 2008 and 2008 R2, SEHOP is activated by default
; the exception handler chain is tested for the presence of ntdll.dll!FinalExceptionHandler
; at its end by RaiseException all seh-handlers are disregarded if not present and the
; program is aborted
assume fs:nothing
; load NT_TIB into ECX
mov ecx, fs:[0h]
assume fs:error
walk:
; load 'next' member of current SEH into EDX
mov edx, [ecx]
; test if 'next' of current SEH is last (== 0xffffffff)
inc edx
jz found
dec edx
; exchange content; ECX contains address of next SEH
xchg edx, ecx
; inspect next SEH
jmp walk
found:
; load 'handler' member of SEH == address of last SEH handler installed by Windows
mov ecx, [ecx+04h]
; save address in ECX as SEH handler for context
mov [eax+03ch], ecx
; set ECX to -1
mov ecx, 0ffffffffh
; save ECX as next SEH item
mov [eax+038h], ecx
; load address of next SEH item
lea ecx, [eax+038h]
; save next SEH
mov [eax+018h], ecx
ret ; return pointer to context-data
trampoline:
; move transport_t for entering context-function
; FCTX == EAX, DATA == EDX
mov [esp], eax
mov [esp+04h], edx
push ebp
; jump to context-function
jmp ebx
finish:
; exit code is zero
xor eax, eax
mov [esp], eax
; exit application
call _exit
hlt
make_fcontext ENDP
END
-107
View File
@@ -1,107 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* ---------------------------------------------------------------------------------- *
* | to | data | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.file "make_i386_sysv_elf_gas.S"
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
make_fcontext:
/* first arg of make_fcontext() == top of context-stack */
movl 0x4(%esp), %eax
/* reserve space for first argument of context-function
eax might already point to a 16byte border */
leal -0x8(%eax), %eax
/* shift address in EAX to lower 16 byte boundary */
andl $-16, %eax
/* reserve space for context-data on context-stack */
leal -0x28(%eax), %eax
/* third arg of make_fcontext() == address of context-function */
/* stored in EBX */
movl 0xc(%esp), %ecx
movl %ecx, 0x10(%eax)
/* save MMX control- and status-word */
stmxcsr (%eax)
/* save x87 control-word */
fnstcw 0x4(%eax)
/* return transport_t */
/* FCTX == EDI, DATA == ESI */
leal 0x8(%eax), %ecx
movl %ecx, 0x1c(%eax)
/* compute abs address of label trampoline */
call 1f
/* address of trampoline 1 */
1: popl %ecx
/* compute abs address of label trampoline */
addl $trampoline-1b, %ecx
/* save address of trampoline as return address */
/* will be entered after calling jump_fcontext() first time */
movl %ecx, 0x18(%eax)
/* compute abs address of label finish */
call 2f
/* address of label 2 */
2: popl %ecx
/* compute abs address of label finish */
addl $finish-2b, %ecx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movl %ecx, 0x14(%eax)
ret /* return pointer to context-data */
trampoline:
/* move transport_t for entering context-function */
movl %edi, (%esp)
movl %esi, 0x4(%esp)
pushl %ebp
/* jump to context-function */
jmp *%ebx
finish:
call 3f
/* address of label 3 */
3: popl %ebx
/* compute address of GOT and store it in EBX */
addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx
/* exit code is zero */
xorl %eax, %eax
movl %eax, (%esp)
/* exit application */
call _exit@PLT
hlt
.size make_fcontext,.-make_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-90
View File
@@ -1,90 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | to | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | | *
* ---------------------------------------------------------------------------------- *
* | data | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
.text
.globl _make_fcontext
.align 2
_make_fcontext:
/* first arg of make_fcontext() == top of context-stack */
movl 0x4(%esp), %eax
/* reserve space for first argument of context-function
eax might already point to a 16byte border */
leal -0x8(%eax), %eax
/* shift address in EAX to lower 16 byte boundary */
andl $-16, %eax
/* reserve space for context-data on context-stack */
leal -0x2c(%eax), %eax
/* third arg of make_fcontext() == address of context-function */
/* stored in EBX */
movl 0xc(%esp), %ecx
movl %ecx, 0x10(%eax)
/* save MMX control- and status-word */
stmxcsr (%eax)
/* save x87 control-word */
fnstcw 0x4(%eax)
/* compute abs address of label trampoline */
call 1f
/* address of trampoline 1 */
1: popl %ecx
/* compute abs address of label trampoline */
addl $trampoline-1b, %ecx
/* save address of trampoline as return address */
/* will be entered after calling jump_fcontext() first time */
movl %ecx, 0x18(%eax)
/* compute abs address of label finish */
call 2f
/* address of label 2 */
2: popl %ecx
/* compute abs address of label finish */
addl $finish-2b, %ecx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movl %ecx, 0x14(%eax)
ret /* return pointer to context-data */
trampoline:
/* move transport_t for entering context-function */
movl %eax, (%esp)
movl %edx, 0x4(%esp)
pushl %ebp
/* jump to context-function */
jmp *%ebx
finish:
/* exit code is zero */
xorl %eax, %eax
movl %eax, (%esp)
/* exit application */
call __exit
hlt
-97
View File
@@ -1,97 +0,0 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* | F20 | F22 | F24 | F26 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | F28 | F30 | S0 | S1 | S2 | S3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | S4 | S5 | S6 | S7 | FP |hiddn| RA | PC | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | ABI ARGS | GP | FCTX| DATA| | *
* ------------------------------------------------- *
* *
* *****************************************************/
.file "make_mips32_o32_elf_gas.S"
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
.ent make_fcontext
make_fcontext:
#ifdef __PIC__
.set noreorder
.cpload $t9
.set reorder
#endif
# shift address in A0 to lower 16 byte boundary
li $v1, -16 # 0xfffffffffffffff0
and $v0, $v1, $a0
# reserve space for context-data on context-stack
# includes an extra 32 bytes for:
# - 16-byte incoming argument area required by mips ABI used when
# jump_context calls the initial function
# - 4 bytes to save our GP register used in finish
# - 8 bytes to as space for transfer_t returned to finish
# - 4 bytes for alignment
addiu $v0, $v0, -128
# third arg of make_fcontext() == address of context-function
sw $a2, 92($v0)
# save global pointer in context-data
sw $gp, 112($v0)
# compute address of returned transfer_t
addiu $t0, $v0, 116
sw $t0, 84($v0)
# compute abs address of label finish
la $t9, finish
# save address of finish as return-address for context-function
# will be entered after context-function returns
sw $t9, 88($v0)
jr $ra # return pointer to context-data
finish:
# reload our gp register (needed for la)
lw $gp, 16($sp)
# call _exit(0)
# the previous function should have left the 16 bytes incoming argument
# area on the stack which we reuse for calling _exit
la $t9, _exit
move $a0, $zero
jr $t9
.end make_fcontext
.size make_fcontext, .-make_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
Loaded 100 of 20827 files, more files were not shown because too many files have changed in this diff. Show more