Compare commits

..
Author SHA1 Message Date
George Schlossnagle ef4573eaf2 white space changes (s/ /\t/g) 2002-10-23 07:12:13 +00:00
George Schlossnagle c382dbbac6 fixed directory merging 2002-10-23 06:07:07 +00:00
George Schlossnagle d9647606fb fixed return values for php_response_handler 2002-10-09 02:57:33 +00:00
George Schlossnagle a4ec6e9fa1 headers code cleanup 2002-10-08 06:42:54 +00:00
George Schlossnagle 7adb8e0ba9 header code cleanup 2002-10-08 06:25:02 +00:00
George Schlossnagle b85162590d sync with head. add optional content type param to send_http_header 2002-10-08 02:17:02 +00:00
George Schlossnagle 868773aa3d sync with head 2002-10-08 02:16:25 +00:00
George Schlossnagle 2306fe934d Cleaned up a bunch of code, fully integrated the class::method handler
code into a single stack per handlers (for correct interleaving).

Changed the syntax so that now they are of the form

phpUriHandler /filename
phpUriHandlerMethod Class::Method

This now works for all handlers including response handlers.
2002-08-30 19:12:28 +00:00
George Schlossnagle b0e2b8604f added the ability to set handlers as class methods (classes will need to be
declared in a phpRequire statemenet, of course, or be otherwise available
at the hook run-time (builtins)).  This is currently only implemented
for the uri trans handler  it is usable as:

phpUriHandlerCodeRef MyClass::MyMethod

This can be greatly robustified from whre it stands now, but is a good proof
of concept (hopefully!)
2002-08-29 20:23:07 +00:00
George Schlossnagle d44619a811 added all the sub_request methods and logging methods 2002-08-28 21:23:12 +00:00
George Schlossnagle 2bc1d055cb Added wrapper functions for the majority of the apache API_EXPORT functions
as class methods for the ApacheRequest objects.  broke sapi_activate
into two functions to allow for reading of headers/cookies separately
from request bodies (POST stuff).  Altered some of the send_headers code
in mod_php4.c to prevent sending headers twice (since a phpResponseHandler
needs to be able to have full freedom for setting headers using the
ap_*_header* functions.
2002-08-28 18:56:51 +00:00
George Schlossnagle 0a105b4130 added wrapper for ap_send_http_header so that phpResponseHandler is now
working.  Added protections to mod_php4's internal call to the same so
that headers cannot be accidentally sent twice.
2002-08-28 04:37:37 +00:00
George Schlossnagle 22528c9e59 This handler works much better when not commented out. :) 2002-08-28 03:55:42 +00:00
George Schlossnagle 4030dc1224 All handlers are now 'stacked' allowing for multiple handlers to be called in the
order they are listed in the httpd.conf for a section.  phpRequire is now supported (called out of the post-read request handler), and a first attempt at phpResponseHandler, a response-time type handler which is set by a

<Location blah>
SetHandler php-script
phpResponseHandler /tmp/foo.php
</Location>

To allow for the stacked handlers, the entirety of zend_stack.c was imported into mod_php4.c.  There is a patch pending to zend_stack.c to add the functionality so that all the redundant code can be removed.
2002-08-27 20:57:09 +00:00
George Schlossnagle b185cac59d Replaced handler loading commands such that what was
php_value uri_handler /tmp/foo.php

is now

phpUriHandler	/tmp/foo.php

This fixes some bugs that caused handlers to be skipped or mysteriously 'unloaded',
reduces the number of calls to zend_alter_ini_entries that are necessary, as well
as allows for easier implementation of stacked handlers (which comes next).

Added 2 new hooks, phpPostReadHandler and phpHeaderHandler (going to the obvious places).
2002-08-27 14:41:53 +00:00
lukas schroeder dc0ad431c8 - add interface functions for headers_in, headers_out and err_headers_out 2002-08-26 23:49:15 +00:00
lukas schroeder f3f7b97826 - put common sapi startup code into a function 2002-08-26 23:14:21 +00:00
George Schlossnagle f05126e2cf Import of Lukas Schroeder's work to give php a full interface to apache 1.3.x's hook interface, and full class wrappers around the apache request object and it's interfaces. 2002-08-26 20:06:31 +00:00
George Schlossnagle ea996e0fa6 new full apache-1.3.x hooks interface support initial import 2002-08-26 20:02:18 +00:00
SVN Migration 025580f68a This commit was manufactured by cvs2svn to create branch 'apache_hooks'. 2002-08-22 07:56:40 +00:00
Rasmus Lerdorf 15611c1885 Ok, get it onto the right branch
(cvs can get annoying sometimes)
2001-09-06 23:39:02 +00:00
Rasmus Lerdorf 2797cf1323 Apache request handler hook framework. So far only the uri hook is
implemented, but the others will be easy once I finish the uri translation
example.  The big things left to do is to create a proper $r request
object to be manipulated in user-space and also to verify that the hooks
don't steal the POST data such that it isn't available to the content
handler once it is finally called.  Or if we do steal it, make sure it
is somehow available to the content handler later on.

Comments and help with this stuff is more than welcome.  Check out these
files from the 'apache_hooks' branch to play along.
2001-09-06 09:53:34 +00:00
SVN Migration 22f9e24408 This commit was manufactured by cvs2svn to create branch 'apache_hooks'. 2001-08-31 22:03:25 +00:00
20357 changed files with 5229 additions and 3963069 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
-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!
-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
-------------------------------------------------------------------------------
-68
View File
@@ -1,68 +0,0 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2021 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
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 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
acknowledgment:
"This product includes PHP software, freely available from
<http://www.php.net/software/>".
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
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
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.
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>.
-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! >>>
-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
-96
View File
@@ -1,96 +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 "make_mips64_n64_elf_gas.S"
.text
.globl make_fcontext
.align 3
.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, 0xfffffffffffffff0
and $v0, $v1, $a0
# reserve space for context-data on context-stack
daddiu $v0, $v0, -160
# third arg of make_fcontext() == address of context-function
sd $a2, 152($v0)
# save global pointer in context-data
sd $gp, 136($v0)
# psudo instruction compute abs address of label finish based on GP
dla $t9, finish
# save address of finish as return-address for context-function
# will be entered after context-function returns
sd $t9, 144($v0)
jr $ra # return pointer to context-data
finish:
# reload our gp register (needed for la)
daddiu $t0, $sp, -160
ld $gp, 136($t0)
# call _exit(0)
# the previous function should have left the 16 bytes incoming argument
# area on the stack which we reuse for calling _exit
dla $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
-146
View File
@@ -1,146 +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 "make_ppc32_sysv_elf_gas.S"
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
make_fcontext:
# save return address into R6
mflr %r6
# first arg of make_fcontext() == top address of context-function
# shift address in R3 to lower 16 byte boundary
clrrwi %r3, %r3, 4
# reserve space on context-stack, including 16 bytes of linkage
# and parameter area + 240 bytes of context-data (R1 % 16 == 0)
subi %r3, %r3, 16 + 240
# third arg of make_fcontext() == address of context-function
#ifdef __linux__
# save context-function as PC
stw %r5, 16(%r3)
#else
# save context-function for trampoline
stw %r5, 248(%r3)
#endif
# set back-chain to zero
li %r0, 0
stw %r0, 240(%r3)
# copy FPSCR to new context
mffs %f0
stfd %f0, 8(%r3)
#ifdef __linux__
# set hidden pointer for returning transfer_t
la %r0, 248(%r3)
stw %r0, 4(%r3)
#endif
# load address of label 1 into R4
bl 1f
1: mflr %r4
#ifndef __linux__
# compute abs address of trampoline, use as PC
addi %r7, %r4, trampoline - 1b
stw %r7, 16(%r3)
#endif
# compute abs address of label finish
addi %r4, %r4, finish - 1b
# save address of finish as return-address for context-function
# will be entered after context-function returns
stw %r4, 244(%r3)
# restore return address from R6
mtlr %r6
blr # return pointer to context-data
#ifndef __linux__
trampoline:
# On systems other than Linux, jump_fcontext is returning the
# transfer_t in R3:R4, but we need to pass transfer_t * R3 to
# our context-function.
lwz %r0, 8(%r1) # address of context-function
mtctr %r0
stw %r3, 8(%r1)
stw %r4, 12(%r1)
la %r3, 8(%r1) # address of transfer_t
bctr
#endif
finish:
# Use the secure PLT for _exit(0). If we use the insecure BSS PLT
# here, then the linker may use the insecure BSS PLT even if the
# C++ compiler wanted the secure PLT.
# set R30 for secure PLT, large model
bl 2f
2: mflr %r30
addis %r30, %r30, .Ltoc - 2b@ha
addi %r30, %r30, .Ltoc - 2b@l
# call _exit(0) with special addend 0x8000 for large model
li %r3, 0
bl _exit + 0x8000@plt
.size make_fcontext, .-make_fcontext
/* Provide the GOT pointer for secure PLT, large model. */
.section .got2,"aw"
.Ltoc = . + 0x8000
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-137
View File
@@ -1,137 +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 _make_fcontext
.align 2
_make_fcontext:
# save return address into R6
mflr r6
# first arg of make_fcontext() == top address of context-function
# shift address in R3 to lower 16 byte boundary
clrrwi r3, r3, 4
# reserve space for context-data on context-stack
# including 64 byte of linkage + parameter area (R1 16 == 0)
subi r3, r3, 336
# third arg of make_fcontext() == address of context-function
stw r5, 240(r3)
# set back-chain to zero
li r0, 0
stw r0, 244(r3)
mffs f0 # load FPSCR
stfd f0, 144(r3) # save FPSCR
# compute address of returned transfer_t
addi r0, r3, 252
mr r4, r0
stw r4, 228(r3)
# load LR
mflr r0
# jump to label 1
bl 1f
1:
# load LR into R4
mflr r4
# compute abs address of label finish
addi r4, r4, finish - 1b
# restore LR
mtlr r0
# save address of finish as return-address for context-function
# will be entered after context-function returns
stw r4, 236(r3)
# restore return address from R6
mtlr r6
blr # return pointer to context-data
finish:
# save return address into R0
mflr r0
# save return address on stack, set up stack frame
stw r0, 4(r1)
# allocate stack space, R1 16 == 0
stwu r1, -16(r1)
# exit code is zero
li r3, 0
# exit application
bl _exit@plt
-177
View File
@@ -1,177 +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 "make_ppc64_sysv_elf_gas.S"
.globl make_fcontext
#if _CALL_ELF == 2
.text
.align 2
make_fcontext:
addis %r2, %r12, .TOC.-make_fcontext@ha
addi %r2, %r2, .TOC.-make_fcontext@l
.localentry make_fcontext, . - make_fcontext
#else
.section ".opd","aw"
.align 3
make_fcontext:
# ifdef _CALL_LINUX
.quad .L.make_fcontext,.TOC.@tocbase,0
.type make_fcontext,@function
.text
.align 2
.L.make_fcontext:
# else
.hidden .make_fcontext
.globl .make_fcontext
.quad .make_fcontext,.TOC.@tocbase,0
.size make_fcontext,24
.type .make_fcontext,@function
.text
.align 2
.make_fcontext:
# endif
#endif
# save return address into R6
mflr %r6
# first arg of make_fcontext() == top address of context-stack
# shift address in R3 to lower 16 byte boundary
clrrdi %r3, %r3, 4
# reserve space for context-data on context-stack
# including 64 byte of linkage + parameter area (R1 % 16 == 0)
subi %r3, %r3, 248
# third arg of make_fcontext() == address of context-function
# entry point (ELFv2) or descriptor (ELFv1)
#if _CALL_ELF == 2
# save address of context-function entry point
std %r5, 176(%r3)
#else
# save address of context-function entry point
ld %r4, 0(%r5)
std %r4, 176(%r3)
# save TOC of context-function
ld %r4, 8(%r5)
std %r4, 0(%r3)
#endif
# set back-chain to zero
li %r0, 0
std %r0, 184(%r3)
#if _CALL_ELF != 2
# zero in r3 indicates first jump to context-function
std %r0, 152(%r3)
#endif
# load LR
mflr %r0
# jump to label 1
bl 1f
1:
# load LR into R4
mflr %r4
# compute abs address of label finish
addi %r4, %r4, finish - 1b
# restore LR
mtlr %r0
# save address of finish as return-address for context-function
# will be entered after context-function returns
std %r4, 168(%r3)
# restore return address from R6
mtlr %r6
blr # return pointer to context-data
finish:
# save return address into R0
mflr %r0
# save return address on stack, set up stack frame
std %r0, 8(%r1)
# allocate stack space, R1 % 16 == 0
stdu %r1, -32(%r1)
# exit code is zero
li %r3, 0
# exit application
bl _exit
nop
#if _CALL_ELF == 2
.size make_fcontext, .-make_fcontext
#else
# ifdef _CALL_LINUX
.size .make_fcontext, .-.L.make_fcontext
# else
.size .make_fcontext, .-.make_fcontext
# endif
#endif
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-126
View File
@@ -1,126 +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
.globl _make_fcontext
_make_fcontext:
; save return address into R6
mflr r6
; first arg of make_fcontext() == top address of context-function
; shift address in R3 to lower 16 byte boundary
clrrwi r3, r3, 4
; reserve space for context-data on context-stack
; including 64 byte of linkage + parameter area (R1 16 == 0)
subi r3, r3, 248
; third arg of make_fcontext() == address of context-function
stw r5, 176(r3)
; set back-chain to zero
li %r0, 0
std %r0, 184(%r3)
; compute address of returned transfer_t
addi %r0, %r3, 232
mr %r4, %r0
std %r4, 152(%r3)
; load LR
mflr r0
; jump to label 1
bl l1
l1:
; load LR into R4
mflr r4
; compute abs address of label finish
addi r4, r4, lo16((finish - .) + 4)
; restore LR
mtlr r0
; save address of finish as return-address for context-function
; will be entered after context-function returns
std r4, 168(r3)
; restore return address from R6
mtlr r6
blr ; return pointer to context-data
finish:
; save return address into R0
mflr r0
; save return address on stack, set up stack frame
stw r0, 8(r1)
; allocate stack space, R1 16 == 0
stwu r1, -32(r1)
; set return value to zero
li r3, 0
; exit application
bl __exit
nop
-108
View File
@@ -1,108 +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 make_fcontext
.type make_fcontext, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
#define R14_OFFSET 88
#define FP_OFFSET 96
#define FPC_OFFSET 160
#define PC_OFFSET 168
#define CONTEXT_SIZE 176
/*
fcontext_t make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) );
Create and return a context below SP to call FN.
Incoming args
r2 - The stack location where to create the context
r3 - The size of the context
r4 - The address of the context function
*/
make_fcontext:
.machine "z10"
/* Align the stack to an 8 byte boundary. */
nill %r2,0xfff0
/* Allocate stack space for the context. */
aghi %r2,-CONTEXT_SIZE
/* Set the r2 save slot to zero. This indicates jump_fcontext
that this is a special context. */
mvghi GR_OFFSET(%r2),0
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r2)
/* Store the address of the target function as new pc. */
stg %r4,PC_OFFSET(%r2)
/* Store a pointer to the finish routine as r14. If a function
called via context routines just returns that value will be
loaded and used as return address. Hence the program will
just exit. */
larl %r1,finish
stg %r1,R14_OFFSET(%r2)
/* Return as usual with the new context returned in r2. */
br %r14
finish:
/* In finish tasks, you load the exit code and exit the
make_fcontext This is called when the context-function is
entirely executed. */
lghi %r2,0
brasl %r14,_exit@PLT
.size make_fcontext,.-make_fcontext
.section .note.GNU-stack,"",%progbits
-163
View File
@@ -1,163 +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 | |
; ----------------------------------------------------------------------------------
; standard C library function
EXTERN _exit:PROC
.code
; generate function table entry in .pdata and unwind information in
make_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
; .xdata for a function's structured exception handling unwind behavior
.endprolog
; first arg of make_fcontext() == top of context-stack
mov rax, rcx
; shift address in RAX to lower 16 byte boundary
; == pointer to fcontext_t and address of context stack
and rax, -16
; reserve space for context-data on context-stack
; on context-function entry: (RSP -0x8) % 16 == 0
sub rax, 0150h
; third arg of make_fcontext() == address of context-function
; stored in RBX
mov [rax+0100h], r8
; first arg of make_fcontext() == top of context-stack
; save top address of context stack as 'base'
mov [rax+0c8h], rcx
; second arg of make_fcontext() == size of context-stack
; negate stack size for LEA instruction (== substraction)
neg rdx
; compute bottom address of context stack (limit)
lea rcx, [rcx+rdx]
; save bottom address of context stack as 'limit'
mov [rax+0c0h], rcx
; save address of context stack limit as 'dealloction stack'
mov [rax+0b8h], rcx
; set fiber-storage to zero
xor rcx, rcx
mov [rax+0b0h], rcx
; save MMX control- and status-word
stmxcsr [rax+0a0h]
; save x87 control-word
fnstcw [rax+0a4h]
; compute address of transport_t
lea rcx, [rax+0140h]
; store address of transport_t in hidden field
mov [rax+0110h], rcx
; compute abs address of label trampoline
lea rcx, trampoline
; save address of trampoline as return-address for context-function
; will be entered after calling jump_fcontext() first time
mov [rax+0118h], rcx
; compute abs address of label finish
lea rcx, finish
; save address of finish as return-address for context-function in RBP
; will be entered after context-function returns
mov [rax+0108h], rcx
ret ; return pointer to context-data
trampoline:
; store return address on stack
; fix stack alignment
push rbp
; jump to context-function
jmp rbx
finish:
; exit code is zero
xor rcx, rcx
; exit application
call _exit
hlt
make_fcontext ENDP
END
-82
View File
@@ -1,82 +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 "make_x86_64_sysv_elf_gas.S"
.text
.globl make_fcontext
.type make_fcontext,@function
.align 16
make_fcontext:
/* first arg of make_fcontext() == top of context-stack */
movq %rdi, %rax
/* shift address in RAX to lower 16 byte boundary */
andq $-16, %rax
/* reserve space for context-data on context-stack */
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x40(%rax), %rax
/* third arg of make_fcontext() == address of context-function */
/* stored in RBX */
movq %rdx, 0x28(%rax)
/* save MMX control- and status-word */
stmxcsr (%rax)
/* save x87 control-word */
fnstcw 0x4(%rax)
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of trampoline as return-address for context-function */
/* will be entered after calling jump_fcontext() first time */
movq %rcx, 0x38(%rax)
/* compute abs address of label finish */
leaq finish(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movq %rcx, 0x30(%rax)
ret /* return pointer to context-data */
trampoline:
/* store return address on stack */
/* fix stack alignment */
push %rbp
/* jump to context-function */
jmp *%rbx
finish:
/* exit code is zero */
xorq %rdi, %rdi
/* exit application */
call _exit@PLT
hlt
.size make_fcontext,.-make_fcontext
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-76
View File
@@ -1,76 +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 _make_fcontext
.align 8
_make_fcontext:
/* first arg of make_fcontext() == top of context-stack */
movq %rdi, %rax
/* shift address in RAX to lower 16 byte boundary */
andq $-16, %rax
/* reserve space for context-data on context-stack */
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x40(%rax), %rax
/* third arg of make_fcontext() == address of context-function */
/* stored in RBX */
movq %rdx, 0x28(%rax)
/* save MMX control- and status-word */
stmxcsr (%rax)
/* save x87 control-word */
fnstcw 0x4(%rax)
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of trampoline as return-address for context-function */
/* will be entered after calling jump_fcontext() first time */
movq %rcx, 0x38(%rax)
/* compute abs address of label finish */
leaq finish(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movq %rcx, 0x30(%rax)
ret /* return pointer to context-data */
trampoline:
/* store return address on stack */
/* fix stack alignment */
push %rbp
/* jump to context-function */
jmp *%rbx
finish:
/* exit code is zero */
xorq %rdi, %rdi
/* exit application */
call __exit
hlt
-422
View File
@@ -1,422 +0,0 @@
<?php
if (function_exists("date_default_timezone_set")) {
date_default_timezone_set("UTC");
}
function simple() {
$a = 0;
for ($i = 0; $i < 1000000; $i++)
$a++;
$thisisanotherlongname = 0;
for ($thisisalongname = 0; $thisisalongname < 1000000; $thisisalongname++)
$thisisanotherlongname++;
}
/****/
function simplecall() {
for ($i = 0; $i < 1000000; $i++)
strlen("hallo");
}
/****/
function hallo($a) {
}
function simpleucall() {
for ($i = 0; $i < 1000000; $i++)
hallo("hallo");
}
/****/
function simpleudcall() {
for ($i = 0; $i < 1000000; $i++)
hallo2("hallo");
}
function hallo2($a) {
}
/****/
function mandel() {
$w1=50;
$h1=150;
$recen=-.45;
$imcen=0.0;
$r=0.7;
$s=0; $rec=0; $imc=0; $re=0; $im=0; $re2=0; $im2=0;
$x=0; $y=0; $w2=0; $h2=0; $color=0;
$s=2*$r/$w1;
$w2=40;
$h2=12;
for ($y=0 ; $y<=$w1; $y=$y+1) {
$imc=$s*($y-$h2)+$imcen;
for ($x=0 ; $x<=$h1; $x=$x+1) {
$rec=$s*($x-$w2)+$recen;
$re=$rec;
$im=$imc;
$color=1000;
$re2=$re*$re;
$im2=$im*$im;
while( ((($re2+$im2)<1000000) && $color>0)) {
$im=$re*$im*2+$imc;
$re=$re2-$im2+$rec;
$re2=$re*$re;
$im2=$im*$im;
$color=$color-1;
}
if ( $color==0 ) {
print "_";
} else {
print "#";
}
}
print "<br>";
flush();
}
}
/****/
function mandel2() {
$b = " .:,;!/>)|&IH%*#";
//float r, i, z, Z, t, c, C;
for ($y=30; printf("\n"), $C = $y*0.1 - 1.5, $y--;){
for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ < 75;){
for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k<5000; $k++)
if ($z*$z + $Z*$Z > 500000) break;
echo $b[$k%16];
}
}
}
/****/
function Ack($m, $n){
if($m == 0) return $n+1;
if($n == 0) return Ack($m-1, 1);
return Ack($m - 1, Ack($m, ($n - 1)));
}
function ackermann($n) {
$r = Ack(3,$n);
print "Ack(3,$n): $r\n";
}
/****/
function ary($n) {
for ($i=0; $i<$n; $i++) {
$X[$i] = $i;
}
for ($i=$n-1; $i>=0; $i--) {
$Y[$i] = $X[$i];
}
$last = $n-1;
print "$Y[$last]\n";
}
/****/
function ary2($n) {
for ($i=0; $i<$n;) {
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
$X[$i] = $i; ++$i;
}
for ($i=$n-1; $i>=0;) {
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
$Y[$i] = $X[$i]; --$i;
}
$last = $n-1;
print "$Y[$last]\n";
}
/****/
function ary3($n) {
for ($i=0; $i<$n; $i++) {
$X[$i] = $i + 1;
$Y[$i] = 0;
}
for ($k=0; $k<1000; $k++) {
for ($i=$n-1; $i>=0; $i--) {
$Y[$i] += $X[$i];
}
}
$last = $n-1;
print "$Y[0] $Y[$last]\n";
}
/****/
function fibo_r($n){
return(($n < 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));
}
function fibo($n) {
$r = fibo_r($n);
print "$r\n";
}
/****/
function hash1($n) {
for ($i = 1; $i <= $n; $i++) {
$X[dechex($i)] = $i;
}
$c = 0;
for ($i = $n; $i > 0; $i--) {
if ($X[dechex($i)]) { $c++; }
}
print "$c\n";
}
/****/
function hash2($n) {
for ($i = 0; $i < $n; $i++) {
$hash1["foo_$i"] = $i;
$hash2["foo_$i"] = 0;
}
for ($i = $n; $i > 0; $i--) {
foreach($hash1 as $key => $value) $hash2[$key] += $value;
}
$first = "foo_0";
$last = "foo_".($n-1);
print "$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n";
}
/****/
function gen_random ($n) {
global $LAST;
return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );
}
function heapsort_r($n, &$ra) {
$l = ($n >> 1) + 1;
$ir = $n;
while (1) {
if ($l > 1) {
$rra = $ra[--$l];
} else {
$rra = $ra[$ir];
$ra[$ir] = $ra[1];
if (--$ir == 1) {
$ra[1] = $rra;
return;
}
}
$i = $l;
$j = $l << 1;
while ($j <= $ir) {
if (($j < $ir) && ($ra[$j] < $ra[$j+1])) {
$j++;
}
if ($rra < $ra[$j]) {
$ra[$i] = $ra[$j];
$j += ($i = $j);
} else {
$j = $ir + 1;
}
}
$ra[$i] = $rra;
}
}
function heapsort($N) {
global $LAST;
define("IM", 139968);
define("IA", 3877);
define("IC", 29573);
$LAST = 42;
for ($i=1; $i<=$N; $i++) {
$ary[$i] = gen_random(1);
}
heapsort_r($N, $ary);
printf("%.10f\n", $ary[$N]);
}
/****/
function mkmatrix ($rows, $cols) {
$count = 1;
$mx = array();
for ($i=0; $i<$rows; $i++) {
for ($j=0; $j<$cols; $j++) {
$mx[$i][$j] = $count++;
}
}
return($mx);
}
function mmult ($rows, $cols, $m1, $m2) {
$m3 = array();
for ($i=0; $i<$rows; $i++) {
for ($j=0; $j<$cols; $j++) {
$x = 0;
for ($k=0; $k<$cols; $k++) {
$x += $m1[$i][$k] * $m2[$k][$j];
}
$m3[$i][$j] = $x;
}
}
return($m3);
}
function matrix($n) {
$SIZE = 30;
$m1 = mkmatrix($SIZE, $SIZE);
$m2 = mkmatrix($SIZE, $SIZE);
while ($n--) {
$mm = mmult($SIZE, $SIZE, $m1, $m2);
}
print "{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n";
}
/****/
function nestedloop($n) {
$x = 0;
for ($a=0; $a<$n; $a++)
for ($b=0; $b<$n; $b++)
for ($c=0; $c<$n; $c++)
for ($d=0; $d<$n; $d++)
for ($e=0; $e<$n; $e++)
for ($f=0; $f<$n; $f++)
$x++;
print "$x\n";
}
/****/
function sieve($n) {
$count = 0;
while ($n-- > 0) {
$count = 0;
$flags = range (0,8192);
for ($i=2; $i<8193; $i++) {
if ($flags[$i] > 0) {
for ($k=$i+$i; $k <= 8192; $k+=$i) {
$flags[$k] = 0;
}
$count++;
}
}
}
print "Count: $count\n";
}
/****/
function strcat($n) {
$str = "";
while ($n-- > 0) {
$str .= "hello\n";
}
$len = strlen($str);
print "$len\n";
}
/*****/
function gethrtime()
{
$hrtime = hrtime();
return (($hrtime[0]*1000000000 + $hrtime[1]) / 1000000000);
}
function start_test()
{
ob_start();
return gethrtime();
}
function end_test($start, $name)
{
global $total;
$end = gethrtime();
ob_end_clean();
$total += $end-$start;
$num = number_format($end-$start,3);
$pad = str_repeat(" ", 24-strlen($name)-strlen($num));
echo $name.$pad.$num."\n";
ob_start();
return gethrtime();
}
function total()
{
global $total;
$pad = str_repeat("-", 24);
echo $pad."\n";
$num = number_format($total,3);
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num));
echo "Total".$pad.$num."\n";
}
$t0 = $t = start_test();
simple();
$t = end_test($t, "simple");
simplecall();
$t = end_test($t, "simplecall");
simpleucall();
$t = end_test($t, "simpleucall");
simpleudcall();
$t = end_test($t, "simpleudcall");
mandel();
$t = end_test($t, "mandel");
mandel2();
$t = end_test($t, "mandel2");
ackermann(7);
$t = end_test($t, "ackermann(7)");
ary(50000);
$t = end_test($t, "ary(50000)");
ary2(50000);
$t = end_test($t, "ary2(50000)");
ary3(2000);
$t = end_test($t, "ary3(2000)");
fibo(30);
$t = end_test($t, "fibo(30)");
hash1(50000);
$t = end_test($t, "hash1(50000)");
hash2(500);
$t = end_test($t, "hash2(500)");
heapsort(20000);
$t = end_test($t, "heapsort(20000)");
matrix(20);
$t = end_test($t, "matrix(20)");
nestedloop(12);
$t = end_test($t, "nestedloop(12)");
sieve(30);
$t = end_test($t, "sieve(30)");
strcat(200000);
$t = end_test($t, "strcat(200000)");
total();
?>
-358
View File
@@ -1,358 +0,0 @@
<?php
function hallo() {
}
function simpleucall($n) {
for ($i = 0; $i < $n; $i++)
hallo();
}
function simpleudcall($n) {
for ($i = 0; $i < $n; $i++)
hallo2();
}
function hallo2() {
}
function simpleicall($n) {
for ($i = 0; $i < $n; $i++)
func_num_args();
}
class Foo {
static $a = 0;
public $b = 0;
const TEST = 0;
static function read_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = self::$a;
}
}
static function write_static($n) {
for ($i = 0; $i < $n; ++$i) {
self::$a = 0;
}
}
static function isset_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = isset(self::$a);
}
}
static function empty_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = empty(self::$a);
}
}
static function f() {
}
static function call_static($n) {
for ($i = 0; $i < $n; ++$i) {
self::f();
}
}
function read_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$x = $this->b;
}
}
function write_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$this->b = 0;
}
}
function assign_add_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$this->b += 2;
}
}
function pre_inc_prop($n) {
for ($i = 0; $i < $n; ++$i) {
++$this->b;
}
}
function pre_dec_prop($n) {
for ($i = 0; $i < $n; ++$i) {
--$this->b;
}
}
function post_inc_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$this->b++;
}
}
function post_dec_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$this->b--;
}
}
function isset_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$x = isset($this->b);
}
}
function empty_prop($n) {
for ($i = 0; $i < $n; ++$i) {
$x = empty($this->b);
}
}
function g() {
}
function call($n) {
for ($i = 0; $i < $n; ++$i) {
$this->g();
}
}
function read_const($n) {
for ($i = 0; $i < $n; ++$i) {
$x = $this::TEST;
}
}
}
function read_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = Foo::$a;
}
}
function write_static($n) {
for ($i = 0; $i < $n; ++$i) {
Foo::$a = 0;
}
}
function isset_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = isset(Foo::$a);
}
}
function empty_static($n) {
for ($i = 0; $i < $n; ++$i) {
$x = empty(Foo::$a);
}
}
function call_static($n) {
for ($i = 0; $i < $n; ++$i) {
Foo::f();
}
}
function create_object($n) {
for ($i = 0; $i < $n; ++$i) {
$x = new Foo();
}
}
define('TEST', null);
function read_const($n) {
for ($i = 0; $i < $n; ++$i) {
$x = TEST;
}
}
function read_auto_global($n) {
for ($i = 0; $i < $n; ++$i) {
$x = $_GET;
}
}
$g_var = 0;
function read_global_var($n) {
for ($i = 0; $i < $n; ++$i) {
$x = $GLOBALS['g_var'];
}
}
function read_hash($n) {
$hash = array('test' => 0);
for ($i = 0; $i < $n; ++$i) {
$x = $hash['test'];
}
}
function read_str_offset($n) {
$str = "test";
for ($i = 0; $i < $n; ++$i) {
$x = $str[1];
}
}
function issetor($n) {
$val = array(0,1,2,3,4,5,6,7,8,9);
for ($i = 0; $i < $n; ++$i) {
$x = $val ?: null;
}
}
function issetor2($n) {
$f = false; $j = 0;
for ($i = 0; $i < $n; ++$i) {
$x = $f ?: $j + 1;
}
}
function ternary($n) {
$val = array(0,1,2,3,4,5,6,7,8,9);
$f = false;
for ($i = 0; $i < $n; ++$i) {
$x = $f ? null : $val;
}
}
function ternary2($n) {
$f = false; $j = 0;
for ($i = 0; $i < $n; ++$i) {
$x = $f ? $f : $j + 1;
}
}
/*****/
function empty_loop($n) {
for ($i = 0; $i < $n; ++$i) {
}
}
function gethrtime()
{
$hrtime = hrtime();
return (($hrtime[0]*1000000000 + $hrtime[1]) / 1000000000);
}
function start_test()
{
ob_start();
return gethrtime();
}
function end_test($start, $name, $overhead = null)
{
global $total;
global $last_time;
$end = gethrtime();
ob_end_clean();
$last_time = $end-$start;
$total += $last_time;
$num = number_format($last_time,3);
$pad = str_repeat(" ", 24-strlen($name)-strlen($num));
if (is_null($overhead)) {
echo $name.$pad.$num."\n";
} else {
$num2 = number_format($last_time - $overhead,3);
echo $name.$pad.$num." ".$num2."\n";
}
ob_start();
return gethrtime();
}
function total()
{
global $total;
$pad = str_repeat("-", 24);
echo $pad."\n";
$num = number_format($total,3);
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num));
echo "Total".$pad.$num."\n";
}
const N = 5000000;
$t0 = $t = start_test();
empty_loop(N);
$t = end_test($t, 'empty_loop');
$overhead = $last_time;
simpleucall(N);
$t = end_test($t, 'func()', $overhead);
simpleudcall(N);
$t = end_test($t, 'undef_func()', $overhead);
simpleicall(N);
$t = end_test($t, 'int_func()', $overhead);
Foo::read_static(N);
$t = end_test($t, '$x = self::$x', $overhead);
Foo::write_static(N);
$t = end_test($t, 'self::$x = 0', $overhead);
Foo::isset_static(N);
$t = end_test($t, 'isset(self::$x)', $overhead);
Foo::empty_static(N);
$t = end_test($t, 'empty(self::$x)', $overhead);
read_static(N);
$t = end_test($t, '$x = Foo::$x', $overhead);
write_static(N);
$t = end_test($t, 'Foo::$x = 0', $overhead);
isset_static(N);
$t = end_test($t, 'isset(Foo::$x)', $overhead);
empty_static(N);
$t = end_test($t, 'empty(Foo::$x)', $overhead);
Foo::call_static(N);
$t = end_test($t, 'self::f()', $overhead);
call_static(N);
$t = end_test($t, 'Foo::f()', $overhead);
$x = new Foo();
$x->read_prop(N);
$t = end_test($t, '$x = $this->x', $overhead);
$x->write_prop(N);
$t = end_test($t, '$this->x = 0', $overhead);
$x->assign_add_prop(N);
$t = end_test($t, '$this->x += 2', $overhead);
$x->pre_inc_prop(N);
$t = end_test($t, '++$this->x', $overhead);
$x->pre_dec_prop(N);
$t = end_test($t, '--$this->x', $overhead);
$x->post_inc_prop(N);
$t = end_test($t, '$this->x++', $overhead);
$x->post_dec_prop(N);
$t = end_test($t, '$this->x--', $overhead);
$x->isset_prop(N);
$t = end_test($t, 'isset($this->x)', $overhead);
$x->empty_prop(N);
$t = end_test($t, 'empty($this->x)', $overhead);
$x->call(N);
$t = end_test($t, '$this->f()', $overhead);
$x->read_const(N);
$t = end_test($t, '$x = Foo::TEST', $overhead);
create_object(N);
$t = end_test($t, 'new Foo()', $overhead);
read_const(N);
$t = end_test($t, '$x = TEST', $overhead);
read_auto_global(N);
$t = end_test($t, '$x = $_GET', $overhead);
read_global_var(N);
$t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead);
read_hash(N);
$t = end_test($t, '$x = $hash[\'v\']', $overhead);
read_str_offset(N);
$t = end_test($t, '$x = $str[0]', $overhead);
issetor(N);
$t = end_test($t, '$x = $a ?: null', $overhead);
issetor2(N);
$t = end_test($t, '$x = $f ?: tmp', $overhead);
ternary(N);
$t = end_test($t, '$x = $f ? $f : $a', $overhead);
ternary2(N);
$t = end_test($t, '$x = $f ? $f : tmp', $overhead);
total($t0, "Total");
Loaded 100 of 20357 files, more files were not shown because too many files have changed in this diff. Show more