summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS38
-rw-r--r--NEWS-5.5344
-rw-r--r--README.RELEASE_PROCESS10
-rwxr-xr-xUPGRADING4
-rw-r--r--UPGRADING.INTERNALS8
-rw-r--r--Zend/tests/bug55156.phpt3
-rw-r--r--Zend/tests/bug61025.phpt27
-rw-r--r--Zend/tests/bug62343.phpt13
-rw-r--r--Zend/tests/bug63976.phpt20
-rw-r--r--Zend/tests/bug64239_1.phpt22
-rw-r--r--Zend/tests/bug64354.phpt24
-rw-r--r--Zend/tests/bug64417.phpt39
-rw-r--r--Zend/tests/generators/errors/serialize_unserialize_error.phpt2
-rw-r--r--Zend/tests/generators/generator_with_nonscalar_keys.phpt52
-rw-r--r--Zend/tests/ns_026.phpt2
-rw-r--r--Zend/zend.h7
-rw-r--r--Zend/zend_API.c73
-rw-r--r--Zend/zend_API.h2
-rw-r--r--Zend/zend_builtin_functions.c38
-rw-r--r--Zend/zend_closures.c1
-rw-r--r--Zend/zend_closures.h2
-rw-r--r--Zend/zend_compile.c10
-rw-r--r--Zend/zend_compile.h1
-rw-r--r--Zend/zend_generators.c24
-rw-r--r--Zend/zend_hash.c18
-rw-r--r--Zend/zend_hash.h4
-rw-r--r--Zend/zend_interfaces.c40
-rw-r--r--Zend/zend_interfaces.h2
-rw-r--r--Zend/zend_iterators.h7
-rw-r--r--Zend/zend_types.h1
-rw-r--r--Zend/zend_vm_def.h96
-rw-r--r--Zend/zend_vm_execute.h174
-rwxr-xr-xconfigure915
-rw-r--r--configure.in2
-rw-r--r--ext/com_dotnet/com_iterator.c9
-rw-r--r--ext/com_dotnet/com_saproxy.c9
-rw-r--r--ext/date/lib/timezonedb.h1209
-rw-r--r--ext/date/php_date.c359
-rw-r--r--ext/date/php_date.h2
-rw-r--r--ext/date/tests/bug45682.phpt20
-rw-r--r--ext/date/tests/bug48678.phpt18
-rw-r--r--ext/date/tests/bug49081.phpt7
-rw-r--r--ext/date/tests/bug49778.phpt16
-rw-r--r--ext/date/tests/bug52113.phpt165
-rw-r--r--ext/date/tests/bug52738.phpt7
-rw-r--r--ext/date/tests/bug52808.phpt54
-rw-r--r--ext/date/tests/bug53437.phpt134
-rw-r--r--ext/date/tests/bug53437_var1.phpt13
-rw-r--r--ext/date/tests/bug53437_var2.phpt80
-rw-r--r--ext/date/tests/bug53437_var3.phpt45
-rw-r--r--ext/date/tests/bug55397.phpt3
-rw-r--r--ext/date/tests/bug62852.phpt26
-rw-r--r--ext/date/tests/bug62852_var2.phpt25
-rw-r--r--ext/date/tests/bug62852_var3.phpt25
-rw-r--r--ext/date/tests/date_diff1.phpt18
-rw-r--r--ext/dom/dom_iterators.c27
-rw-r--r--ext/intl/breakiterator/breakiterator_iterators.cpp10
-rw-r--r--ext/intl/common/common_enum.cpp14
-rw-r--r--ext/intl/resourcebundle/resourcebundle_iterator.c13
-rw-r--r--ext/mysqli/mysqli_result_iterator.c5
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c2
-rw-r--r--ext/oci8/php_oci8_int.h2
-rw-r--r--ext/opcache/Optimizer/block_pass.c2028
-rw-r--r--ext/opcache/Optimizer/nop_removal.c126
-rw-r--r--ext/opcache/Optimizer/optimize_temp_vars_5.c222
-rw-r--r--ext/opcache/Optimizer/pass10.c3
-rw-r--r--ext/opcache/Optimizer/pass1_5.c391
-rw-r--r--ext/opcache/Optimizer/pass2.c211
-rw-r--r--ext/opcache/Optimizer/pass3.c442
-rw-r--r--ext/opcache/Optimizer/pass5.c3
-rw-r--r--ext/opcache/Optimizer/pass9.c8
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c139
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.h49
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h83
-rw-r--r--ext/opcache/README202
-rw-r--r--ext/opcache/ZendAccelerator.c2656
-rw-r--r--ext/opcache/ZendAccelerator.h382
-rw-r--r--ext/opcache/config.m4346
-rw-r--r--ext/opcache/config.w3227
-rw-r--r--ext/opcache/shared_alloc_mmap.c78
-rw-r--r--ext/opcache/shared_alloc_posix.c98
-rw-r--r--ext/opcache/shared_alloc_shm.c145
-rw-r--r--ext/opcache/shared_alloc_win32.c340
-rw-r--r--ext/opcache/tests/001_cli.phpt19
-rw-r--r--ext/opcache/tests/bug64353.phpt29
-rw-r--r--ext/opcache/tests/issue0057.phpt38
-rw-r--r--ext/opcache/tests/skipif.inc3
-rw-r--r--ext/opcache/zend_accelerator_blacklist.c261
-rw-r--r--ext/opcache/zend_accelerator_blacklist.h49
-rw-r--r--ext/opcache/zend_accelerator_debug.c99
-rw-r--r--ext/opcache/zend_accelerator_debug.h33
-rw-r--r--ext/opcache/zend_accelerator_hash.c224
-rw-r--r--ext/opcache/zend_accelerator_hash.h98
-rw-r--r--ext/opcache/zend_accelerator_module.c618
-rw-r--r--ext/opcache/zend_accelerator_module.h28
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.c1007
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.h49
-rw-r--r--ext/opcache/zend_persist.c680
-rw-r--r--ext/opcache/zend_persist.h29
-rw-r--r--ext/opcache/zend_persist_calc.c343
-rw-r--r--ext/opcache/zend_shared_alloc.c489
-rw-r--r--ext/opcache/zend_shared_alloc.h186
-rw-r--r--ext/pcre/php_pcre.c2
-rw-r--r--ext/pdo/pdo_stmt.c9
-rw-r--r--ext/pdo_mysql/mysql_statement.c20
-rw-r--r--ext/phar/phar_object.c50
-rw-r--r--ext/phar/tests/create_new_and_modify.phpt8
-rw-r--r--ext/phar/tests/delete_in_phar.phpt9
-rw-r--r--ext/phar/tests/delete_in_phar_confirm.phpt9
-rw-r--r--ext/phar/tests/tar/create_new_and_modify.phpt8
-rw-r--r--ext/phar/tests/tar/delete_in_phar.phpt8
-rw-r--r--ext/phar/tests/tar/delete_in_phar_confirm.phpt8
-rw-r--r--ext/phar/tests/zip/create_new_and_modify.phpt8
-rw-r--r--ext/phar/tests/zip/delete_in_phar.phpt8
-rw-r--r--ext/phar/tests/zip/delete_in_phar_confirm.phpt8
-rw-r--r--ext/reflection/tests/005.phpt3
-rw-r--r--ext/reflection/tests/009.phpt3
-rw-r--r--ext/reflection/tests/025.phpt3
-rw-r--r--ext/reflection/tests/ReflectionClass_getDocComment_001.phpt3
-rw-r--r--ext/reflection/tests/ReflectionFunction_getDocComment.001.phpt3
-rw-r--r--ext/reflection/tests/ReflectionMethod_getDocComment_basic.phpt3
-rw-r--r--ext/reflection/tests/ReflectionProperty_basic2.phpt3
-rw-r--r--ext/reflection/tests/ReflectionProperty_getDocComment_basic.phpt3
-rw-r--r--ext/reflection/tests/bug36308.phpt3
-rw-r--r--ext/simplexml/simplexml.c29
-rw-r--r--ext/snmp/snmp.c4
-rw-r--r--ext/snmp/tests/ipv6.phpt4
-rw-r--r--ext/snmp/tests/snmp-object.phpt20
-rw-r--r--ext/soap/php_encoding.c19
-rw-r--r--ext/spl/spl_array.c24
-rw-r--r--ext/spl/spl_directory.c20
-rw-r--r--ext/spl/spl_dllist.c73
-rw-r--r--ext/spl/spl_fixedarray.c8
-rw-r--r--ext/spl/spl_heap.c5
-rw-r--r--ext/spl/spl_iterators.c171
-rw-r--r--ext/spl/spl_iterators.h5
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_add_invalid_offset.phpt13
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_add_missing_parameter1.phpt11
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_add_missing_parameter2.phpt11
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_add_null_offset.phpt13
-rw-r--r--ext/spl/tests/dllist_013.phpt45
-rw-r--r--ext/spl/tests/iterator_to_array_nonscalar_keys.phpt31
-rw-r--r--ext/spl/tests/multiple_iterator_001.phpt20
-rw-r--r--ext/standard/array.c189
-rw-r--r--ext/standard/basic_functions.c7
-rw-r--r--ext/standard/php_array.h1
-rw-r--r--ext/standard/tests/array/array_column_basic.phpt307
-rw-r--r--ext/standard/tests/array/array_column_error.phpt98
-rw-r--r--ext/standard/tests/array/uasort_variation9.phpt2
-rw-r--r--ext/standard/tests/bug64370_var1.phpt21
-rw-r--r--ext/standard/tests/bug64370_var2.phpt23
-rw-r--r--ext/standard/tests/serialize/bug64354_1.phpt25
-rw-r--r--ext/standard/tests/serialize/bug64354_2.phpt24
-rw-r--r--ext/standard/tests/serialize/bug64354_3.phpt29
-rw-r--r--ext/standard/var.c22
-rw-r--r--ext/standard/var_unserializer.c30
-rw-r--r--ext/standard/var_unserializer.re28
-rw-r--r--ext/zip/lib/zip_close.c6
-rw-r--r--ext/zip/lib/zip_dirent.c12
-rw-r--r--generated_lists2
-rw-r--r--main/network.c2
-rw-r--r--main/php_config.h.in27
-rw-r--r--main/php_ini.c21
-rw-r--r--main/php_version.h4
-rwxr-xr-xrun-tests.php1
-rw-r--r--sapi/cli/config.m419
-rw-r--r--sapi/cli/config.w324
-rw-r--r--sapi/cli/php_cli.c18
-rw-r--r--sapi/cli/php_cli_process_title.c80
-rw-r--r--sapi/cli/php_cli_process_title.h43
-rw-r--r--sapi/cli/php_cli_server.c8
-rw-r--r--sapi/cli/php_cli_server.h1
-rw-r--r--sapi/cli/ps_title.c426
-rw-r--r--sapi/cli/ps_title.h42
-rw-r--r--sapi/cli/tests/cli_process_title_unix.phpt49
-rw-r--r--sapi/cli/tests/cli_process_title_windows.phpt82
-rw-r--r--tests/output/ob_017.phpt2
-rw-r--r--tests/output/ob_start_basic_004.phpt2
-rw-r--r--win32/build/mkdist.php2
-rw-r--r--win32/globals.c2
-rw-r--r--win32/php_win32_globals.h4
-rw-r--r--win32/time.c133
182 files changed, 17292 insertions, 1817 deletions
diff --git a/NEWS b/NEWS
index 0d9c242be..5f29170fb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,42 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+21 Mar 2013, PHP 5.5.0 Beta 1
+
+- Core:
+ . Added Zend Opcache extension and enable building it by default.
+ More details here: https://wiki.php.net/rfc/optimizerplus. (Dmitry)
+ . Added array_column function which returns a column in a multidimensional
+ array. https://wiki.php.net/rfc/array_column. (Ben Ramsey)
+ . Fixed bug #64354 (Unserialize array of objects whose class can't
+ be autoloaded fail). (Laruence)
+ . Added support for changing the process's title in CLI/CLI-Server SAPIs.
+ The implementation is more robust that the proctitle PECL module. More
+ details here: https://wiki.php.net/rfc/cli_process_title. (Keyur)
+ . Fixed bug #64370 (microtime(true) less than $_SERVER['REQUEST_TIME_FLOAT']).
+ (Anatol)
+ . Added support for non-scalar Iterator keys in foreach
+ (https://wiki.php.net/rfc/foreach-non-scalar-keys). (Nikita Popov)
+
+- mysqlnd
+ . Fixed bug #63530 (mysqlnd_stmt::bind_one_parameter crashes, uses wrong alloc
+ for stmt->param_bind). (Andrey)
+
+- DateTime
+ . Fixed bug #53437 (Crash when using unserialized DatePeriod instance).
+ (Gustavo, Derick, Anatol)
+ . Fixed bug #62852 (Unserialize Invalid Date causes crash). (Anatol)
+
+- SPL:
+ . Implement FR #48358 (Add SplDoublyLinkedList::add() to insert an element
+ at a given offset). (Mark Baker, David Soria Parra)
+
+- Zip:
+ . Bug #64452 (Zip crash intermittently). (Anatol)
+
07 Mar 2013, PHP 5.5.0 Alpha 6
- Core:
+ . Fixed bug #61025 (__invoke() visibility not honored). (Laruence)
. Fixed bug #49348 (Uninitialized ++$foo->bar; does not cause a notice).
(Stas)
@@ -16,6 +50,10 @@ PHP NEWS
- DateTime:
. Fixed bug #64359 (strftime crash with VS2012). (Anatol)
+- SNMP:
+ . Fixed bug #61981 (OO API, walk: $suffix_as_key is not working correctly).
+ (Boris Lytochkin)
+
21 Feb 2013, PHP 5.5.0 Alpha 5
- Core:
diff --git a/NEWS-5.5 b/NEWS-5.5
deleted file mode 100644
index a5b11c0d3..000000000
--- a/NEWS-5.5
+++ /dev/null
@@ -1,344 +0,0 @@
-PHP NEWS
-|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-?? ??? 201?, PHP 5.5.0 Beta 1
-
-- Core:
- . Fixed bug #49348 (Uninitialized ++$foo->bar; does not cause a notice).
- (Stas)
-
-- Sockets:
- . Fixed bug #64287 (sendmsg/recvmsg shutdown handler causes segfault).
- (Gustavo)
-
-- PCRE:
- . Merged PCRE 8.32. (Anatol)
-
-21 Feb 2013, PHP 5.5.0 Alpha 5
-
-- Core:
- . Implemented FR #64175 (Added HTTP codes as of RFC 6585). (Jonh Wendell)
- . Fixed bug #64135 (Exceptions from set_error_handler are not always
- propagated). (Laruence)
- . Fixed bug #63830 (Segfault on undefined function call in nested generator).
- (Nikita Popov)
- . Fixed bug #60833 (self, parent, static behave inconsistently
- case-sensitive). (Stas, mario at include-once dot org)
- . Implemented FR #60524 (specify temp dir by php.ini). (ALeX Kazik).
- . Fixed bug #64142 (dval to lval different behavior on ppc64). (Remi)
- . Added ARMv7/v8 versions of various Zend arithmetic functions that are
- implemented using inline assembler (Ard Biesheuvel)
- . Fix undefined behavior when converting double variables to integers.
- The double is now always rounded towards zero, the remainder of its division
- by 2^32 or 2^64 (depending on sizeof(long)) is calculated and it's made
- signed assuming a two's complement representation. (Gustavo)
-
-- CLI server:
- . Fixed bug #64128 (buit-in web server is broken on ppc64). (Remi)
-
-- cURL:
- . Implemented FR #46439 - added CURLFile for safer file uploads.
- (Stas)
-
-- Intl:
- . Cherry-picked UConverter wrapper, which had accidentaly been committed only
- to master.
-
-- mysqli
- . Added mysqli_begin_transaction()/mysqli::begin_transaction(). Implemented
- all options, per MySQL 5.6, which can be used with START TRANSACTION, COMMIT
- and ROLLBACK through options to mysqli_commit()/mysqli_rollback() and their
- respective OO counterparts. They work in libmysql and mysqlnd mode. (Andrey)
- . Added mysqli_savepoint(), mysqli_release_savepoint(). (Andrey)
-
-- mysqlnd
- . Add new begin_transaction() call to the connection object. Implemented all
- options, per MySQL 5.6, which can be used with START TRANSACTION, COMMIT
- and ROLLBACK. (Andrey)
- . Added mysqlnd_savepoint(), mysqlnd_release_savepoint(). (Andrey)
-
-- Sockets:
- . Added recvmsg() and sendmsg() wrappers. (Gustavo)
- See https://wiki.php.net/rfc/sendrecvmsg
-
-- Filter:
- . Implemented FR #49180 - added MAC address validation. (Martin)
-
-- Phar:
- . Fixed timestamp update on Phar contents modification. (Dmitry)
-
-- SPL:
- . Fixed bug #64264 (SPLFixedArray toArray problem). (Laruence)
- . Fixed bug #64228 (RecursiveDirectoryIterator always assumes SKIP_DOTS).
- (patch by kriss@krizalys.com, Laruence)
- . Fixed bug #64106 (Segfault on SplFixedArray[][x] = y when extended).
- (Nikita Popov)
- . Fixed bug #52861 (unset fails with ArrayObject and deep arrays).
- (Mike Willbanks)
-
-- SNMP:
- . Fixed bug #64124 (IPv6 malformed). (Boris Lytochkin)
-
-24 Jan 2013, PHP 5.5.0 Alpha 4
-
-- Core:
- . Fixed bug #63980 (object members get trimmed by zero bytes). (Laruence)
- . Implemented RFC for Class Name Resolution As Scalar Via "class" Keyword.
- (Ralph Schindler, Nikita Popov, Lars)
-
-- DateTime
- . Added DateTimeImmutable - a variant of DateTime that only returns the
- modified state instead of changing itself. (Derick)
-
-- FPM:
- . Fixed bug #63999 (php with fpm fails to build on Solaris 10 or 11). (Adam)
-
-- pgsql:
- . Bug #46408: Locale number format settings can cause pg_query_params to
- break with numerics. (asmecher, Lars)
-
-- dba:
- . Bug #62489: dba_insert not working as expected.
- (marc-bennewitz at arcor dot de, Lars)
-
-- Reflection:
- . Fixed bug #64007 (There is an ability to create instance of Generator by
- hand). (Laruence)
-
-10 Jan 2013, PHP 5.5.0 Alpha 3
-
-- General improvements:
- . Fixed bug #63874 (Segfault if php_strip_whitespace has heredoc). (Pierrick)
- . Fixed bug #63822 (Crash when using closures with ArrayAccess).
- (Nikita Popov)
- . Add Generator::throw() method. (Nikita Popov)
- . Bug #23955: allow specifying Max-Age attribute in setcookie() (narfbg, Lars)
- . Bug #52126: timestamp for mail.log (Martin Jansen, Lars)
-
-- mysqlnd
- . Fixed return value of mysqli_stmt_affected_rows() in the time after
- prepare() and before execute(). (Andrey)
-
-- cURL:
- . Added new functions curl_escape, curl_multi_setopt, curl_multi_strerror
- curl_pause, curl_reset, curl_share_close, curl_share_init,
- curl_share_setopt curl_strerror and curl_unescape. (Pierrick)
- . Addes new curl options CURLOPT_TELNETOPTIONS, CURLOPT_GSSAPI_DELEGATION,
- CURLOPT_ACCEPTTIMEOUT_MS, CURLOPT_SSL_OPTIONS, CURLOPT_TCP_KEEPALIVE,
- CURLOPT_TCP_KEEPIDLE and CURLOPT_TCP_KEEPINTVL. (Pierrick)
-
-18 Dec 2012, PHP 5.5.0 Alpha 2
-
-- General improvements:
- . Added systemtap support by enabling systemtap compatible dtrace probes on
- linux. (David Soria Parra)
- . Added support for using empty() on the result of function calls and
- other expressions (https://wiki.php.net/rfc/empty_isset_exprs).
- (Nikita Popov)
- . Optimized access to temporary and compiled VM variables. 8% less memory
- reads. (Dmitry)
- . The VM stacks for passing function arguments and syntaticaly nested calls
- were merged into a single stack. The stack size needed for op_array
- execution is calculated at compile time and preallocated at once. As result
- all the stack push operatins don't require checks for stack overflow
- any more. (Dmitry)
-
-- MySQL
- . This extension is now deprecated, and deprecation warnings will be generated
- when connections are established to databases via mysql_connect(),
- mysql_pconnect(), or through implicit connection: use MySQLi or PDO_MySQL
- instead (https://wiki.php.net/rfc/mysql_deprecation). (Adam)
-
-- Fileinfo:
- . Fixed bug #63590 (Different results in TS and NTS under Windows).
- (Anatoliy)
-
-- Apache2 Handler SAPI:
- . Enabled Apache 2.4 configure option for Windows (Pierre, Anatoliy)
-
-13 Nov 2012, PHP 5.5.0 Alpha 1
-
-- General improvements:
- . Added generators and coroutines (https://wiki.php.net/rfc/generators).
- (Nikita Popov)
- . Added "finally" keyword (https://wiki.php.net/rfc/finally). (Laruence)
- . Add simplified password hashing API
- (https://wiki.php.net/rfc/password_hash). (Anthony Ferrara)
- . Added support for list in foreach (https://wiki.php.net/rfc/foreachlist).
- (Laruence)
- . Added support for using empty() on the result of function calls and
- other expressions (https://wiki.php.net/rfc/empty_isset_exprs).
- (Nikita Popov)
- . Added support for constant array/string dereferencing. (Laruence)
- . Improve set_exception_handler while doing reset.(Laruence)
- . Remove php_logo_guid(), php_egg_logo_guid(), php_real_logo_guid(),
- zend_logo_guid(). (Adnrew Faulds)
- . Drop Windows XP and 2003 support. (Pierre)
-
-- Calendar:
- . Fixed bug #54254 (cal_from_jd returns month = 6 when there is only one Adar)
- (Stas, Eitan Mosenkis)
-
-- Core:
- . Added boolval(). (Jille Timmermans)
- . Added "Z" option to pack/unpack. (Gustavo)
- . Implemented FR #60738 (Allow 'set_error_handler' to handle NULL).
- (Laruence, Nikita Popov)
- . Added optional second argument for assert() to specify custom message. Patch
- by Lonny Kapelushnik (lonny@lonnylot.com). (Lars)
- . Fixed bug #18556 (Engine uses locale rules to handle class names). (Stas)
- . Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence)
- . Fixed bug #61038 (unpack("a5", "str\0\0") does not work as expected).
- (srgoogleguy, Gustavo)
- . Return previous handler when passing NULL to set_error_handler and
- set_exception_handler. (Nikita Popov)
-
-- cURL:
- . Added support for CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPT_APPEND,
- CURLOPT_DIRLISTONLY, CURLOPT_NEW_DIRECTORY_PERMS, CURLOPT_NEW_FILE_PERMS,
- CURLOPT_NETRC_FILE, CURLOPT_PREQUOTE, CURLOPT_KRBLEVEL, CURLOPT_MAXFILESIZE,
- CURLOPT_FTP_ACCOUNT, CURLOPT_COOKIELIST, CURLOPT_IGNORE_CONTENT_LENGTH,
- CURLOPT_CONNECT_ONLY, CURLOPT_LOCALPORT, CURLOPT_LOCALPORTRANGE,
- CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPT_SSL_SESSIONID_CACHE,
- CURLOPT_FTP_SSL_CCC, CURLOPT_HTTP_CONTENT_DECODING,
- CURLOPT_HTTP_TRANSFER_DECODING, CURLOPT_PROXY_TRANSFER_MODE,
- CURLOPT_ADDRESS_SCOPE, CURLOPT_CRLFILE, CURLOPT_ISSUERCERT,
- CURLOPT_USERNAME, CURLOPT_PASSWORD, CURLOPT_PROXYUSERNAME,
- CURLOPT_PROXYPASSWORD, CURLOPT_NOPROXY, CURLOPT_SOCKS5_GSSAPI_NEC,
- CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPT_TFTP_BLKSIZE,
- CURLOPT_SSH_KNOWNHOSTS, CURLOPT_FTP_USE_PRET, CURLOPT_MAIL_FROM,
- CURLOPT_MAIL_RCPT, CURLOPT_RTSP_CLIENT_CSEQ, CURLOPT_RTSP_SERVER_CSEQ,
- CURLOPT_RTSP_SESSION_ID, CURLOPT_RTSP_STREAM_URI, CURLOPT_RTSP_TRANSPORT,
- CURLOPT_RTSP_REQUEST, CURLOPT_RESOLVE, CURLOPT_ACCEPT_ENCODING,
- CURLOPT_TRANSFER_ENCODING, CURLOPT_DNS_SERVERS and CURLOPT_USE_SSL.
- (Pierrick)
- . Fixed bug #55635 (CURLOPT_BINARYTRANSFER no longer used. The constant
- still exists for backward compatibility but is doing nothing). (Pierrick)
- . Fixed bug #54995 (Missing CURLINFO_RESPONSE_CODE support). (Pierrick)
-
-- Datetime
- . Fixed bug #61642 (modify("+5 weekdays") returns Sunday).
- (Dmitri Iouchtchenko)
-
-- Hash
- . Added support for PBKDF2 via hash_pbkdf2(). (Anthony Ferrara)
-
-- Intl
- . The intl extension now requires ICU 4.0+.
- . Added intl.use_exceptions INI directive, which controls what happens when
- global errors are set together with intl.error_level. (Gustavo)
- . MessageFormatter::format() and related functions now accepted named
- arguments and mixed numeric/named arguments in ICU 4.8+. (Gustavo)
- . MessageFormatter::format() and related functions now don't error out when
- an insufficient argument count is provided. Instead, the placeholders will
- remain unsubstituted. (Gustavo)
- . MessageFormatter::parse() and MessageFormat::format() (and their static
- equivalents) don't throw away better than second precision in the arguments.
- (Gustavo)
- . IntlDateFormatter::__construct and datefmt_create() now accept for the
- $timezone argument time zone identifiers, IntlTimeZone objects, DateTimeZone
- objects and NULL. (Gustavo)
- . IntlDateFormatter::__construct and datefmt_create() no longer accept invalid
- timezone identifiers or empty strings. (Gustavo)
- . The default time zone used in IntlDateFormatter::__construct and
- datefmt_create() (when the corresponding argument is not passed or NULL is
- passed) is now the one given by date_default_timezone_get(), not the
- default ICU time zone. (Gustavo)
- . The time zone passed to the IntlDateFormatter is ignored if it is NULL and
- if the calendar passed is an IntlCalendar object -- in this case, the
- IntlCalendar's time zone will be used instead. Otherwise, the time zone
- specified in the $timezone argument is used instead. This does not affect
- old code, as IntlCalendar was introduced in this version. (Gustavo)
- . IntlDateFormatter::__construct and datefmt_create() now accept for the
- $calendar argument also IntlCalendar objects. (Gustavo)
- . IntlDateFormatter::getCalendar() and datefmt_get_calendar() return false
- if the IntlDateFormatter was set up with an IntlCalendar instead of the
- constants IntlDateFormatter::GREGORIAN/TRADITIONAL. IntlCalendar did not
- exist before this version. (Gustavo)
- . IntlDateFormatter::setCalendar() and datefmt_set_calendar() now also accept
- an IntlCalendar object, in which case its time zone is taken. Passing a
- constant is still allowed, and still keeps the time zone. (Gustavo)
- . IntlDateFormatter::setTimeZoneID() and datefmt_set_timezone_id() are
- deprecated. Use IntlDateFormatter::setTimeZone() or datefmt_set_timezone()
- instead. (Gustavo)
- . IntlDateFormatter::format() and datefmt_format() now also accept an
- IntlCalendar object for formatting. (Gustavo)
- . Added the classes: IntlCalendar, IntlGregorianCalendar, IntlTimeZone,
- IntlBreakIterator, IntlRuleBasedBreakIterator and
- IntlCodePointBreakIterator. (Gustavo)
- . Added the functions: intlcal_get_keyword_values_for_locale(),
- intlcal_get_now(), intlcal_get_available_locales(), intlcal_get(),
- intlcal_get_time(), intlcal_set_time(), intlcal_add(),
- intlcal_set_time_zone(), intlcal_after(), intlcal_before(), intlcal_set(),
- intlcal_roll(), intlcal_clear(), intlcal_field_difference(),
- intlcal_get_actual_maximum(), intlcal_get_actual_minimum(),
- intlcal_get_day_of_week_type(), intlcal_get_first_day_of_week(),
- intlcal_get_greatest_minimum(), intlcal_get_least_maximum(),
- intlcal_get_locale(), intlcal_get_maximum(),
- intlcal_get_minimal_days_in_first_week(), intlcal_get_minimum(),
- intlcal_get_time_zone(), intlcal_get_type(),
- intlcal_get_weekend_transition(), intlcal_in_daylight_time(),
- intlcal_is_equivalent_to(), intlcal_is_lenient(), intlcal_is_set(),
- intlcal_is_weekend(), intlcal_set_first_day_of_week(),
- intlcal_set_lenient(), intlcal_equals(),
- intlcal_get_repeated_wall_time_option(),
- intlcal_get_skipped_wall_time_option(),
- intlcal_set_repeated_wall_time_option(),
- intlcal_set_skipped_wall_time_option(), intlcal_from_date_time(),
- intlcal_to_date_time(), intlcal_get_error_code(),
- intlcal_get_error_message(), intlgregcal_create_instance(),
- intlgregcal_set_gregorian_change(), intlgregcal_get_gregorian_change() and
- intlgregcal_is_leap_year(). (Gustavo)
- . Added the functions: intltz_create_time_zone(), intltz_create_default(),
- intltz_get_id(), intltz_get_gmt(), intltz_get_unknown(),
- intltz_create_enumeration(), intltz_count_equivalent_ids(),
- intltz_create_time_zone_id_enumeration(), intltz_get_canonical_id(),
- intltz_get_region(), intltz_get_tz_data_version(),
- intltz_get_equivalent_id(), intltz_use_daylight_time(), intltz_get_offset(),
- intltz_get_raw_offset(), intltz_has_same_rules(), intltz_get_display_name(),
- intltz_get_dst_savings(), intltz_from_date_time_zone(),
- intltz_to_date_time_zone(), intltz_get_error_code(),
- intltz_get_error_message(). (Gustavo)
- . Added the methods: IntlDateFormatter::formatObject(),
- IntlDateFormatter::getCalendarObject(), IntlDateFormatter::getTimeZone(),
- IntlDateFormatter::setTimeZone(). (Gustavo)
- . Added the functions: datefmt_format_object(), datefmt_get_calendar_object(),
- datefmt_get_timezone(), datefmt_set_timezone(),
- datefmt_get_calendar_object(), intlcal_create_instance(). (Gustavo)
-
-- MCrypt
- . mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb() and mcrypt_ofb() now throw
- E_DEPRECATED. (GoogleGuy)
-
-- MySQLi
- . Dropped support for LOAD DATA LOCAL INFILE handlers when using libmysql.
- Known for stability problems. (Andrey)
- . Added support for SHA256 authentication available with MySQL 5.6.6+.
- (Andrey)
-
-- PCRE:
- . Deprecated the /e modifier
- (https://wiki.php.net/rfc/remove_preg_replace_eval_modifier). (Nikita Popov)
- . Fixed bug #63284 (Upgrade PCRE to 8.31). (Anatoliy)
-
-- pgsql
- . Added pg_escape_literal() and pg_escape_identifier() (Yasuo)
-
-- SPL
- . Fix bug #60560 (SplFixedArray un-/serialize, getSize(), count() return 0,
- keys are strings). (Adam)
-
-- Tokenizer:
- . Fixed bug #60097 (token_get_all fails to lex nested heredoc). (Nikita Popov)
-
-- Zip:
- . Upgraded libzip to 0.10.1 (Anatoliy)
-
-- Fileinfo:
- . Fixed bug #63248 (Load multiple magic files from a directory under Windows).
- (Anatoliy)
-
-- General improvements:
- . Implemented FR #46487 (Dereferencing process-handles no longer waits on
- those processes). (Jille Timmermans)
-
-<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
diff --git a/README.RELEASE_PROCESS b/README.RELEASE_PROCESS
index 2512d3a8b..c8eeb4e13 100644
--- a/README.RELEASE_PROCESS
+++ b/README.RELEASE_PROCESS
@@ -154,7 +154,15 @@ origin <branch>``".
11. run: ``./makedist php 5.4.1``, this will export the tree, create configure
and build two tarballs (one gz and one bz2).
-12. Commit those two tarballs to Git (php-distributions.git)
+12. Commit those two tarballs to web/php-distributions.git, then update the git
+ submodule reference in web/php.git:
+ git submodule init;
+ git submodule update;
+ cd distributions;
+ git pull origin master;
+ cd ..;
+ git commit distributions;
+ git push;
13. Once the release has been tagged, contact the PHP Windows development team
(internals-win@lists.php.net) so that Windows binaries can be created. Once
diff --git a/UPGRADING b/UPGRADING
index ee1ff67c8..ca35a99cd 100755
--- a/UPGRADING
+++ b/UPGRADING
@@ -79,6 +79,10 @@ PHP 5.5 UPGRADE NOTES
(https://wiki.php.net/rfc/generators)
- ClassName::class syntax returning full class name for a class as
a string constant. (https://wiki.php.net/rfc/class_name_scalars)
+- Support for changing the process's title in CLI/CLI-Server SAPIs. (Keyur)
+ (https://wiki.php.net/rfc/cli_process_title)
+- Added support for non-scalar Iterator keys in foreach.
+ (https://wiki.php.net/rfc/foreach-non-scalar-keys).
========================================
2. Changes in SAPI modules
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 44cdfaee6..56243d1f8 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -64,6 +64,14 @@ void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare
The extra argument it has (relatively to zend_qsort()) is passed to the
comparison function.
+ d. get_current_key
+
+The signature of the get_current_key iteration handler has been changed to:
+
+void (*get_current_key)(zend_object_iterator *iter, zval *key TSRMLS_DC);
+
+The key should be written into the zval* using the ZVAL_* macros.
+
========================
2. Build system changes
========================
diff --git a/Zend/tests/bug55156.phpt b/Zend/tests/bug55156.phpt
index 6c0ff768d..7d75ce3e9 100644
--- a/Zend/tests/bug55156.phpt
+++ b/Zend/tests/bug55156.phpt
@@ -1,5 +1,8 @@
--TEST--
Bug #55156 (ReflectionClass::getDocComment() returns comment even though the class has none)
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/Zend/tests/bug61025.phpt b/Zend/tests/bug61025.phpt
new file mode 100644
index 000000000..0709c28fb
--- /dev/null
+++ b/Zend/tests/bug61025.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #61025 (__invoke() visibility not honored)
+--FILE--
+<?php
+
+Interface InvokeAble {
+ static function __invoke();
+}
+
+class Bar {
+ private function __invoke() {
+ return __CLASS__;
+ }
+}
+
+$b = new Bar;
+echo $b();
+
+echo $b->__invoke();
+
+?>
+--EXPECTF--
+Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d
+
+Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d
+Bar
+Fatal error: Call to private method Bar::__invoke() from context '' in %sbug61025.php on line %d
diff --git a/Zend/tests/bug62343.phpt b/Zend/tests/bug62343.phpt
new file mode 100644
index 000000000..b0208c4ac
--- /dev/null
+++ b/Zend/tests/bug62343.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Bug #62343 (Show class_alias In get_declared_classes())
+--FILE--
+<?php
+class a { }
+class_alias("a", "b");
+$c = get_declared_classes();
+var_dump(end($c));
+var_dump(prev($c));
+?>
+--EXPECT--
+string(1) "b"
+string(1) "a"
diff --git a/Zend/tests/bug63976.phpt b/Zend/tests/bug63976.phpt
new file mode 100644
index 000000000..0ac09d9b3
--- /dev/null
+++ b/Zend/tests/bug63976.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #63976 (Parent class incorrectly using child constant in class property)
+--FILE--
+<?php
+if (1) {
+ class Foo {
+ const TABLE = "foo";
+ public $table = self::TABLE;
+ }
+}
+if (1) {
+ class Bar extends Foo {
+ const TABLE = "bar";
+ }
+}
+$bar = new Bar();
+var_dump($bar->table);
+?>
+--EXPECT--
+string(3) "foo"
diff --git a/Zend/tests/bug64239_1.phpt b/Zend/tests/bug64239_1.phpt
new file mode 100644
index 000000000..fe58cbd76
--- /dev/null
+++ b/Zend/tests/bug64239_1.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #64239 (get_class_methods() changed behavior)
+--FILE--
+<?php
+class A {
+ public function test() { $this->backtrace(); }
+}
+class B {
+ use T2 { t2method as Bmethod; }
+}
+trait T2 {
+ public function t2method() {
+ }
+}
+var_dump(get_class_methods("B"));
+--EXPECT--
+array(2) {
+ [0]=>
+ string(7) "bmethod"
+ [1]=>
+ string(8) "t2method"
+}
diff --git a/Zend/tests/bug64354.phpt b/Zend/tests/bug64354.phpt
new file mode 100644
index 000000000..03a4b80b4
--- /dev/null
+++ b/Zend/tests/bug64354.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+class B implements Serializable {
+ public function serialize() {
+ throw new Exception("serialize");
+ return NULL;
+ }
+
+ public function unserialize($data) {
+ }
+}
+
+$data = array(new B);
+
+try {
+ serialize($data);
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(9) "serialize"
diff --git a/Zend/tests/bug64417.phpt b/Zend/tests/bug64417.phpt
new file mode 100644
index 000000000..f3ef740b4
--- /dev/null
+++ b/Zend/tests/bug64417.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Bug #64417 (BC break: ArrayAccess::&offsetGet() in a trait causes fatal error)
+--FILE--
+<?php
+trait aa {
+ private $container = array();
+ public function offsetSet($offset, $value) {
+ if (is_null($offset)) {
+ $this->container[] = $value;
+ } else {
+ $this->container[$offset] = $value;
+ }
+ }
+ public function offsetExists($offset) {
+ return isset($this->container[$offset]);
+ }
+ public function offsetUnset($offset) {
+ unset($this->container[$offset]);
+ }
+ public function &offsetGet($offset) {
+ $result = null;
+ if (isset($this->container[$offset])) {
+ $result = &$this->container[$offset];
+ }
+ return $result;
+ }
+}
+
+class obj implements ArrayAccess {
+ use aa;
+}
+
+$o = new obj;
+$o['x'] = 1;
+++$o['x'];
+echo $o['x'], "\n";
+--EXPECT--
+2
+
diff --git a/Zend/tests/generators/errors/serialize_unserialize_error.phpt b/Zend/tests/generators/errors/serialize_unserialize_error.phpt
index a8470b0a6..aa2d4693f 100644
--- a/Zend/tests/generators/errors/serialize_unserialize_error.phpt
+++ b/Zend/tests/generators/errors/serialize_unserialize_error.phpt
@@ -38,8 +38,6 @@ Stack trace:
#1 %s(%d): unserialize('O:9:"Generator"...')
#2 {main}
-
-Notice: unserialize(): Error at offset 19 of 20 bytes in %s on line %d
exception 'Exception' with message 'Unserialization of 'Generator' is not allowed' in %s:%d
Stack trace:
#0 %s(%d): unserialize('C:9:"Generator"...')
diff --git a/Zend/tests/generators/generator_with_nonscalar_keys.phpt b/Zend/tests/generators/generator_with_nonscalar_keys.phpt
new file mode 100644
index 000000000..5ae55a1be
--- /dev/null
+++ b/Zend/tests/generators/generator_with_nonscalar_keys.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Generators can return non-scalar keys
+--FILE--
+<?php
+
+function gen() {
+ yield [1, 2, 3] => [4, 5, 6];
+ yield (object) ['a' => 'b'] => (object) ['b' => 'a'];
+ yield 3.14 => 2.73;
+ yield false => true;
+ yield true => false;
+ yield null => null;
+}
+
+foreach (gen() as $k => $v) {
+ var_dump($k, $v);
+}
+
+?>
+--EXPECT--
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+}
+array(3) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(5)
+ [2]=>
+ int(6)
+}
+object(stdClass)#3 (1) {
+ ["a"]=>
+ string(1) "b"
+}
+object(stdClass)#4 (1) {
+ ["b"]=>
+ string(1) "a"
+}
+float(3.14)
+float(2.73)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+NULL
+NULL
diff --git a/Zend/tests/ns_026.phpt b/Zend/tests/ns_026.phpt
index af2bf2ca5..45f88750e 100644
--- a/Zend/tests/ns_026.phpt
+++ b/Zend/tests/ns_026.phpt
@@ -1,5 +1,7 @@
--TEST--
026: Name ambiguity (class name & namespace name)
+--INI--
+opcache.optimization_level=0
--FILE--
<?php
namespace Foo;
diff --git a/Zend/zend.h b/Zend/zend.h
index aed03d871..36554637e 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -299,7 +299,6 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore
/*
* zval
*/
-typedef struct _zval_struct zval;
typedef struct _zend_class_entry zend_class_entry;
typedef struct _zend_guard {
@@ -365,6 +364,10 @@ struct _zval_struct {
#define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z))
#define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref)
+#if ZEND_DEBUG
+#define zend_always_inline inline
+#define zend_never_inline
+#else
#if defined(__GNUC__)
#if __GNUC__ >= 3
#define zend_always_inline inline __attribute__((always_inline))
@@ -373,7 +376,6 @@ struct _zval_struct {
#define zend_always_inline inline
#define zend_never_inline
#endif
-
#elif defined(_MSC_VER)
#define zend_always_inline __forceinline
#define zend_never_inline
@@ -381,6 +383,7 @@ struct _zval_struct {
#define zend_always_inline inline
#define zend_never_inline
#endif
+#endif /* ZEND_DEBUG */
#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
# define EXPECTED(condition) __builtin_expect(condition, 1)
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 95c90ea75..1f400dea1 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -1051,6 +1051,41 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro
}
/* }}} */
+static int zval_update_class_constant(zval **pp, int is_static, int offset TSRMLS_DC) /* {{{ */
+{
+ if ((Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT ||
+ (Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_ARRAY) {
+ zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry);
+
+ if ((*scope)->parent) {
+ zend_class_entry *ce = *scope;
+ HashPosition pos;
+ zend_property_info *prop_info;
+
+ do {
+ for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
+ zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
+ if (is_static == ((prop_info->flags & ZEND_ACC_STATIC) != 0) &&
+ offset == prop_info->offset) {
+ int ret;
+ zend_class_entry *old_scope = *scope;
+ *scope = prop_info->ce;
+ ret = zval_update_constant(pp, (void*)1 TSRMLS_CC);
+ *scope = old_scope;
+ return ret;
+ }
+ }
+ ce = ce->parent;
+ } while (ce);
+
+ }
+ return zval_update_constant(pp, (void*)1 TSRMLS_CC);
+ }
+ return 0;
+}
+/* }}} */
+
ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
{
if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0 || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) {
@@ -1063,7 +1098,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC
for (i = 0; i < class_type->default_properties_count; i++) {
if (class_type->default_properties_table[i]) {
- zval_update_constant(&class_type->default_properties_table[i], (void**)1 TSRMLS_CC);
+ zval_update_class_constant(&class_type->default_properties_table[i], 0, i TSRMLS_CC);
}
}
@@ -1104,7 +1139,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC
}
for (i = 0; i < class_type->default_static_members_count; i++) {
- zval_update_constant(&CE_STATIC_MEMBERS(class_type)[i], (void**)1 TSRMLS_CC);
+ zval_update_class_constant(&CE_STATIC_MEMBERS(class_type)[i], 1, i TSRMLS_CC);
}
*scope = old_scope;
@@ -1502,6 +1537,40 @@ ZEND_API int add_get_index_stringl(zval *arg, ulong index, const char *str, uint
}
/* }}} */
+ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */
+{
+ int result;
+
+ switch (Z_TYPE_P(key)) {
+ case IS_STRING:
+ result = zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
+ break;
+ case IS_NULL:
+ result = zend_symtable_update(ht, "", 1, &value, sizeof(zval *), NULL);
+ break;
+ case IS_RESOURCE:
+ zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(key), Z_LVAL_P(key));
+ /* break missing intentionally */
+ case IS_BOOL:
+ case IS_LONG:
+ result = zend_hash_index_update(ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
+ break;
+ case IS_DOUBLE:
+ result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), &value, sizeof(zval *), NULL);
+ break;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ result = FAILURE;
+ }
+
+ if (result == SUCCESS) {
+ Z_ADDREF_P(value);
+ }
+
+ return result;
+}
+/* }}} */
+
ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */
{
zval *tmp;
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index fb642c147..c26141b18 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -426,6 +426,8 @@ ZEND_API int add_get_index_double(zval *arg, ulong idx, double d, void **dest);
ZEND_API int add_get_index_string(zval *arg, ulong idx, const char *str, void **dest, int duplicate);
ZEND_API int add_get_index_stringl(zval *arg, ulong idx, const char *str, uint length, void **dest, int duplicate);
+ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value);
+
ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long l TSRMLS_DC);
ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC);
ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC);
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 4d950a203..ee75f521f 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1025,6 +1025,13 @@ ZEND_FUNCTION(get_object_vars)
}
/* }}} */
+static int same_name(const char *key, const char *name, zend_uint name_len)
+{
+ char *lcname = zend_str_tolower_dup(name, name_len);
+ int ret = memcmp(lcname, key, name_len) == 0;
+ efree(lcname);
+ return ret;
+}
/* {{{ proto array get_class_methods(mixed class)
Returns an array of method names for class or class instance. */
@@ -1072,14 +1079,26 @@ ZEND_FUNCTION(get_class_methods)
uint len = strlen(mptr->common.function_name);
/* Do not display old-style inherited constructors */
- if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
- mptr->common.scope == ce ||
- zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING ||
- zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
-
+ if (zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING) {
MAKE_STD_ZVAL(method_name);
ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1);
zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
+ } else if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
+ mptr->common.scope == ce ||
+ zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
+
+ if (mptr->type == ZEND_USER_FUNCTION &&
+ *mptr->op_array.refcount > 1 &&
+ (len != key_len - 1 ||
+ !same_name(key, mptr->common.function_name, len))) {
+ MAKE_STD_ZVAL(method_name);
+ ZVAL_STRINGL(method_name, key, key_len - 1, 1);
+ zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
+ } else {
+ MAKE_STD_ZVAL(method_name);
+ ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1);
+ zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
+ }
}
}
zend_hash_move_forward_ex(&ce->function_table, &pos);
@@ -1625,7 +1644,6 @@ ZEND_FUNCTION(restore_exception_handler)
}
/* }}} */
-
static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
{
zval *array = va_arg(args, zval *);
@@ -1636,7 +1654,13 @@ static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int nu
if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0)
&& (comply_mask == (ce->ce_flags & mask))) {
- add_next_index_stringl(array, ce->name, ce->name_length, 1);
+ if (ce->refcount > 1 &&
+ (ce->name_length != hash_key->nKeyLength - 1 ||
+ !same_name(hash_key->arKey, ce->name, ce->name_length))) {
+ add_next_index_stringl(array, hash_key->arKey, hash_key->nKeyLength - 1, 1);
+ } else {
+ add_next_index_stringl(array, ce->name, ce->name_length, 1);
+ }
}
return ZEND_HASH_APPLY_KEEP;
}
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 0de928333..5faefbd22 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -291,7 +291,6 @@ static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
}
/* }}} */
-
int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
{
zend_closure *closure;
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index c41cf4756..9d50641d2 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -24,8 +24,6 @@
BEGIN_EXTERN_C()
-#define ZEND_INVOKE_FUNC_NAME "__invoke"
-
void zend_register_closure_ce(TSRMLS_D);
extern ZEND_API zend_class_entry *zend_ce_closure;
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index e45419d3f..6df3defb1 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1621,6 +1621,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
}
+ } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
+ }
}
} else {
char *class_lcname;
@@ -1677,6 +1681,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
}
CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
+ }
} else if (!(fn_flags & ZEND_ACC_STATIC)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
}
@@ -3823,7 +3831,7 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
zend_uint other_flags = other_fn->common.scope->ce_flags;
return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
- && zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)
+ && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
&& ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
(other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
}
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 8042dd54e..2295cffab 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -856,6 +856,7 @@ END_EXTERN_C()
#define ZEND_CALLSTATIC_FUNC_NAME "__callstatic"
#define ZEND_TOSTRING_FUNC_NAME "__tostring"
#define ZEND_AUTOLOAD_FUNC_NAME "__autoload"
+#define ZEND_INVOKE_FUNC_NAME "__invoke"
/* The following constants may be combined in CG(compiler_options)
* to change the default compiler behavior */
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index c1dbee124..3f43552f1 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -755,31 +755,17 @@ static void zend_generator_iterator_get_data(zend_object_iterator *iterator, zva
}
/* }}} */
-static int zend_generator_iterator_get_key(zend_object_iterator *iterator, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void zend_generator_iterator_get_key(zend_object_iterator *iterator, zval *key TSRMLS_DC) /* {{{ */
{
zend_generator *generator = (zend_generator *) iterator->data;
zend_generator_ensure_initialized(generator TSRMLS_CC);
- if (!generator->key) {
- return HASH_KEY_NON_EXISTANT;
- }
-
- if (Z_TYPE_P(generator->key) == IS_LONG) {
- *int_key = Z_LVAL_P(generator->key);
- return HASH_KEY_IS_LONG;
- }
-
- if (Z_TYPE_P(generator->key) == IS_STRING) {
- *str_key = estrndup(Z_STRVAL_P(generator->key), Z_STRLEN_P(generator->key));
- *str_key_len = Z_STRLEN_P(generator->key) + 1;
- return HASH_KEY_IS_STRING;
+ if (generator->key) {
+ ZVAL_ZVAL(key, generator->key, 1, 0);
+ } else {
+ ZVAL_NULL(key);
}
-
- /* Waiting for Etienne's patch to allow arbitrary zval keys. Until then
- * error out on non-int and non-string keys. */
- zend_error_noreturn(E_ERROR, "Currently only int and string keys can be yielded");
- return HASH_KEY_NON_EXISTANT; /* Nerver reached */
}
/* }}} */
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
index 0609d707f..bca47b330 100644
--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@ -1171,6 +1171,24 @@ ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index,
return HASH_KEY_NON_EXISTANT;
}
+ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) {
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ p = pos ? (*pos) : ht->pInternalPointer;
+
+ if (!p) {
+ Z_TYPE_P(key) = IS_NULL;
+ } else if (p->nKeyLength) {
+ Z_TYPE_P(key) = IS_STRING;
+ Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char *) p->arKey : estrndup(p->arKey, p->nKeyLength - 1);
+ Z_STRLEN_P(key) = p->nKeyLength - 1;
+ } else {
+ Z_TYPE_P(key) = IS_LONG;
+ Z_LVAL_P(key) = p->h;
+ }
+}
ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
{
diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h
index 88c3bfb42..a0c147f39 100644
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@ -170,13 +170,13 @@ ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint
ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h);
ZEND_API ulong zend_hash_next_free_element(const HashTable *ht);
-
/* traversing */
#define zend_hash_has_more_elements_ex(ht, pos) \
(zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTANT ? FAILURE : SUCCESS)
ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos);
ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos);
+ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos);
ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos);
ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos);
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
@@ -199,6 +199,8 @@ ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr);
zend_hash_move_backwards_ex(ht, NULL)
#define zend_hash_get_current_key(ht, str_index, num_index, duplicate) \
zend_hash_get_current_key_ex(ht, str_index, NULL, num_index, duplicate, NULL)
+#define zend_hash_get_current_key_zval(ht, key) \
+ zend_hash_get_current_key_zval_ex(ht, key, NULL)
#define zend_hash_get_current_key_type(ht) \
zend_hash_get_current_key_type_ex(ht, NULL)
#define zend_hash_get_current_data(ht, pData) \
diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c
index 384b66da4..16751549b 100644
--- a/Zend/zend_interfaces.c
+++ b/Zend/zend_interfaces.c
@@ -195,7 +195,7 @@ static int zend_user_it_get_current_key_default(zend_object_iterator *_iter, cha
/* }}} */
/* {{{ zend_user_it_get_current_key */
-ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key TSRMLS_DC)
{
zend_user_iterator *iter = (zend_user_iterator*)_iter;
zval *object = (zval*)iter->it.data;
@@ -203,42 +203,16 @@ ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **st
zend_call_method_with_0_params(&object, iter->ce, &iter->ce->iterator_funcs.zf_key, "key", &retval);
- if (!retval) {
- *int_key = 0;
- if (!EG(exception))
- {
+ if (retval) {
+ ZVAL_ZVAL(key, retval, 1, 1);
+ } else {
+ if (!EG(exception)) {
zend_error(E_WARNING, "Nothing returned from %s::key()", iter->ce->name);
}
- return HASH_KEY_IS_LONG;
- }
- switch (Z_TYPE_P(retval)) {
- default:
- zend_error(E_WARNING, "Illegal type returned from %s::key()", iter->ce->name);
- case IS_NULL:
- *int_key = 0;
- zval_ptr_dtor(&retval);
- return HASH_KEY_IS_LONG;
- case IS_STRING:
- *str_key = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
- *str_key_len = Z_STRLEN_P(retval)+1;
- zval_ptr_dtor(&retval);
- return HASH_KEY_IS_STRING;
-
- case IS_DOUBLE:
- *int_key = (long)Z_DVAL_P(retval);
- zval_ptr_dtor(&retval);
- return HASH_KEY_IS_LONG;
-
- case IS_RESOURCE:
- case IS_BOOL:
- case IS_LONG:
- *int_key = (long)Z_LVAL_P(retval);
- zval_ptr_dtor(&retval);
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, 0);
}
}
-/* }}} */
/* {{{ zend_user_it_move_forward */
ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC)
@@ -452,7 +426,7 @@ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, zend_uint
zval_ptr_dtor(&retval);
}
- if (result == FAILURE) {
+ if (result == FAILURE && !EG(exception)) {
zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "%s::serialize() must return a string or NULL", ce->name);
}
return result;
diff --git a/Zend/zend_interfaces.h b/Zend/zend_interfaces.h
index 23547951e..ba4bc6ccb 100644
--- a/Zend/zend_interfaces.h
+++ b/Zend/zend_interfaces.h
@@ -51,7 +51,7 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend
ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter TSRMLS_DC);
ZEND_API int zend_user_it_valid(zend_object_iterator *_iter TSRMLS_DC);
-ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key TSRMLS_DC);
ZEND_API void zend_user_it_get_current_data(zend_object_iterator *_iter, zval ***data TSRMLS_DC);
ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC);
ZEND_API void zend_user_it_invalidate_current(zend_object_iterator *_iter TSRMLS_DC);
diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h
index b484102b2..f74068a27 100644
--- a/Zend/zend_iterators.h
+++ b/Zend/zend_iterators.h
@@ -38,8 +38,11 @@ typedef struct _zend_object_iterator_funcs {
/* fetch the item data for the current element */
void (*get_current_data)(zend_object_iterator *iter, zval ***data TSRMLS_DC);
- /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
- int (*get_current_key)(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+ /* fetch the key for the current element (optional, may be NULL). The key
+ * should be written into the provided zval* using the ZVAL_* macros. If
+ * this handler is not provided auto-incrementing integer keys will be
+ * used. */
+ void (*get_current_key)(zend_object_iterator *iter, zval *key TSRMLS_DC);
/* step forwards to next element */
void (*move_forward)(zend_object_iterator *iter TSRMLS_DC);
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 3e68add3d..9cdf31fb3 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -52,6 +52,7 @@ typedef unsigned long zend_uintptr_t;
typedef unsigned int zend_object_handle;
typedef struct _zend_object_handlers zend_object_handlers;
+typedef struct _zval_struct zval;
typedef struct _zend_object_value {
zend_object_handle handle;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 578a319fd..206a2333f 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2839,17 +2839,17 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
if (OP1_TYPE == IS_TMP_VAR) {
FREE_OP1();
}
- } else if (!IS_OP1_TMP_FREE()) { /* Not a temp var */
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
+ } else {
if (OP1_TYPE == IS_CONST ||
- (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
+ OP1_TYPE == IS_TMP_VAR ||
+ PZVAL_IS_REF(retval_ptr)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
- zval_copy_ctor(ret);
+ if (OP1_TYPE != IS_TMP_VAR) {
+ zval_copy_ctor(ret);
+ }
*EG(return_value_ptr_ptr) = ret;
} else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
@@ -2861,16 +2861,6 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
- } else {
- zval *ret;
-
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
- ALLOC_ZVAL(ret);
- INIT_PZVAL_COPY(ret, retval_ptr);
- *EG(return_value_ptr_ptr) = ret;
}
FREE_OP1_IF_VAR();
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
@@ -2886,10 +2876,6 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
SAVE_OPLINE();
do {
- if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
@@ -4245,13 +4231,13 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
zend_free_op free_op1;
zval *array = EX_T(opline->op1.var).fe.ptr;
zval **value;
- char *str_key;
- uint str_key_len;
- ulong int_key;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
- int key_type = 0;
- zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY);
+
+ zval *key = NULL;
+ if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
+ key = &EX_T((opline+1)->result.var).tmp_var;
+ }
SAVE_OPLINE();
@@ -4262,8 +4248,11 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
case ZEND_ITER_PLAIN_OBJECT: {
- const char *class_name, *prop_name;
zend_object *zobj = zend_objects_get_address(array TSRMLS_CC);
+ int key_type;
+ char *str_key;
+ zend_uint str_key_len;
+ zend_ulong int_key;
fe_ht = Z_OBJPROP_P(array);
zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
@@ -4275,15 +4264,23 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL);
zend_hash_move_forward(fe_ht);
- } while (key_type == HASH_KEY_NON_EXISTANT ||
- (key_type != HASH_KEY_IS_LONG &&
- zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS));
- zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
- if (use_key && key_type != HASH_KEY_IS_LONG) {
- zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len);
- str_key = estrndup(prop_name, str_key_len);
- str_key_len++;
+ } while (key_type != HASH_KEY_IS_LONG &&
+ zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS);
+
+ if (key) {
+ if (key_type == HASH_KEY_IS_LONG) {
+ ZVAL_LONG(key, int_key);
+ } else {
+ const char *class_name, *prop_name;
+ int prop_name_len;
+ zend_unmangle_property_name_ex(
+ str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len
+ );
+ ZVAL_STRINGL(key, prop_name, prop_name_len, 1);
+ }
}
+
+ zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
break;
}
@@ -4294,8 +4291,8 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
/* reached end of iteration */
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
}
- if (use_key) {
- key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL);
+ if (key) {
+ zend_hash_get_current_key_zval(fe_ht, key);
}
zend_hash_move_forward(fe_ht);
zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
@@ -4330,16 +4327,15 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
/* failure in get_current_data */
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
}
- if (use_key) {
+ if (key) {
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ iter->funcs->get_current_key(iter, key TSRMLS_CC);
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(&array);
HANDLE_EXCEPTION();
}
} else {
- key_type = HASH_KEY_IS_LONG;
- int_key = iter->index;
+ ZVAL_LONG(key, iter->index);
}
}
break;
@@ -4355,26 +4351,6 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
AI_SET_PTR(&EX_T(opline->result.var), *value);
}
- if (use_key) {
- zval *key = &EX_T((opline+1)->result.var).tmp_var;
-
- switch (key_type) {
- case HASH_KEY_IS_STRING:
- Z_STRVAL_P(key) = (char*)str_key;
- Z_STRLEN_P(key) = str_key_len-1;
- Z_TYPE_P(key) = IS_STRING;
- break;
- case HASH_KEY_IS_LONG:
- Z_LVAL_P(key) = int_key;
- Z_TYPE_P(key) = IS_LONG;
- break;
- default:
- case HASH_KEY_NON_EXISTANT:
- ZVAL_NULL(key);
- break;
- }
- }
-
CHECK_EXCEPTION();
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 392569678..d65dfc41f 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -2333,17 +2333,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
if (IS_CONST == IS_TMP_VAR) {
}
- } else if (!0) { /* Not a temp var */
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
+ } else {
if (IS_CONST == IS_CONST ||
- (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
+ IS_CONST == IS_TMP_VAR ||
+ PZVAL_IS_REF(retval_ptr)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
- zval_copy_ctor(ret);
+ if (IS_CONST != IS_TMP_VAR) {
+ zval_copy_ctor(ret);
+ }
*EG(return_value_ptr_ptr) = ret;
} else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
@@ -2355,16 +2355,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
- } else {
- zval *ret;
-
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
- ALLOC_ZVAL(ret);
- INIT_PZVAL_COPY(ret, retval_ptr);
- *EG(return_value_ptr_ptr) = ret;
}
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -2380,10 +2370,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
SAVE_OPLINE();
do {
- if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
@@ -7654,17 +7640,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
if (IS_TMP_VAR == IS_TMP_VAR) {
zval_dtor(free_op1.var);
}
- } else if (!1) { /* Not a temp var */
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
+ } else {
if (IS_TMP_VAR == IS_CONST ||
- (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
+ IS_TMP_VAR == IS_TMP_VAR ||
+ PZVAL_IS_REF(retval_ptr)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
- zval_copy_ctor(ret);
+ if (IS_TMP_VAR != IS_TMP_VAR) {
+ zval_copy_ctor(ret);
+ }
*EG(return_value_ptr_ptr) = ret;
} else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
@@ -7676,16 +7662,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
- } else {
- zval *ret;
-
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
- ALLOC_ZVAL(ret);
- INIT_PZVAL_COPY(ret, retval_ptr);
- *EG(return_value_ptr_ptr) = ret;
}
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -7701,10 +7677,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE
SAVE_OPLINE();
do {
- if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
@@ -12888,17 +12860,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
if (IS_VAR == IS_TMP_VAR) {
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
}
- } else if (!0) { /* Not a temp var */
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
+ } else {
if (IS_VAR == IS_CONST ||
- (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
+ IS_VAR == IS_TMP_VAR ||
+ PZVAL_IS_REF(retval_ptr)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
- zval_copy_ctor(ret);
+ if (IS_VAR != IS_TMP_VAR) {
+ zval_copy_ctor(ret);
+ }
*EG(return_value_ptr_ptr) = ret;
} else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
@@ -12910,16 +12882,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
- } else {
- zval *ret;
-
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
- ALLOC_ZVAL(ret);
- INIT_PZVAL_COPY(ret, retval_ptr);
- *EG(return_value_ptr_ptr) = ret;
}
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -12935,10 +12897,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE
SAVE_OPLINE();
do {
- if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
@@ -13588,13 +13546,13 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
zval *array = EX_T(opline->op1.var).fe.ptr;
zval **value;
- char *str_key;
- uint str_key_len;
- ulong int_key;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
- int key_type = 0;
- zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY);
+
+ zval *key = NULL;
+ if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
+ key = &EX_T((opline+1)->result.var).tmp_var;
+ }
SAVE_OPLINE();
@@ -13605,8 +13563,11 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
case ZEND_ITER_PLAIN_OBJECT: {
- const char *class_name, *prop_name;
zend_object *zobj = zend_objects_get_address(array TSRMLS_CC);
+ int key_type;
+ char *str_key;
+ zend_uint str_key_len;
+ zend_ulong int_key;
fe_ht = Z_OBJPROP_P(array);
zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
@@ -13618,15 +13579,23 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL);
zend_hash_move_forward(fe_ht);
- } while (key_type == HASH_KEY_NON_EXISTANT ||
- (key_type != HASH_KEY_IS_LONG &&
- zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS));
- zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
- if (use_key && key_type != HASH_KEY_IS_LONG) {
- zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len);
- str_key = estrndup(prop_name, str_key_len);
- str_key_len++;
+ } while (key_type != HASH_KEY_IS_LONG &&
+ zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS);
+
+ if (key) {
+ if (key_type == HASH_KEY_IS_LONG) {
+ ZVAL_LONG(key, int_key);
+ } else {
+ const char *class_name, *prop_name;
+ int prop_name_len;
+ zend_unmangle_property_name_ex(
+ str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len
+ );
+ ZVAL_STRINGL(key, prop_name, prop_name_len, 1);
+ }
}
+
+ zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
break;
}
@@ -13637,8 +13606,8 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* reached end of iteration */
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
}
- if (use_key) {
- key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL);
+ if (key) {
+ zend_hash_get_current_key_zval(fe_ht, key);
}
zend_hash_move_forward(fe_ht);
zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos);
@@ -13673,16 +13642,15 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* failure in get_current_data */
ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num);
}
- if (use_key) {
+ if (key) {
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ iter->funcs->get_current_key(iter, key TSRMLS_CC);
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(&array);
HANDLE_EXCEPTION();
}
} else {
- key_type = HASH_KEY_IS_LONG;
- int_key = iter->index;
+ ZVAL_LONG(key, iter->index);
}
}
break;
@@ -13698,26 +13666,6 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
AI_SET_PTR(&EX_T(opline->result.var), *value);
}
- if (use_key) {
- zval *key = &EX_T((opline+1)->result.var).tmp_var;
-
- switch (key_type) {
- case HASH_KEY_IS_STRING:
- Z_STRVAL_P(key) = (char*)str_key;
- Z_STRLEN_P(key) = str_key_len-1;
- Z_TYPE_P(key) = IS_STRING;
- break;
- case HASH_KEY_IS_LONG:
- Z_LVAL_P(key) = int_key;
- Z_TYPE_P(key) = IS_LONG;
- break;
- default:
- case HASH_KEY_NON_EXISTANT:
- ZVAL_NULL(key);
- break;
- }
- }
-
CHECK_EXCEPTION();
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
@@ -30534,17 +30482,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
if (IS_CV == IS_TMP_VAR) {
}
- } else if (!0) { /* Not a temp var */
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
+ } else {
if (IS_CV == IS_CONST ||
- (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
+ IS_CV == IS_TMP_VAR ||
+ PZVAL_IS_REF(retval_ptr)) {
zval *ret;
ALLOC_ZVAL(ret);
INIT_PZVAL_COPY(ret, retval_ptr);
- zval_copy_ctor(ret);
+ if (IS_CV != IS_TMP_VAR) {
+ zval_copy_ctor(ret);
+ }
*EG(return_value_ptr_ptr) = ret;
} else if ((IS_CV == IS_CV || IS_CV == IS_VAR) &&
retval_ptr == &EG(uninitialized_zval)) {
@@ -30556,16 +30504,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
*EG(return_value_ptr_ptr) = retval_ptr;
Z_ADDREF_P(retval_ptr);
}
- } else {
- zval *ret;
-
- if (*EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
- ALLOC_ZVAL(ret);
- INIT_PZVAL_COPY(ret, retval_ptr);
- *EG(return_value_ptr_ptr) = ret;
}
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -30581,10 +30519,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER
SAVE_OPLINE();
do {
- if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
- zval_ptr_dtor(EG(return_value_ptr_ptr));
- }
-
if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
/* Not supposed to happen, but we'll allow it */
zend_error(E_NOTICE, "Only variable references should be returned by reference");
diff --git a/configure b/configure
index a0c3972c0..cc19b8a3f 100755
--- a/configure
+++ b/configure
@@ -1048,6 +1048,7 @@ with_iodbc
with_esoob
with_unixODBC
with_dbmaker
+enable_opcache
enable_pcntl
enable_pdo
with_pdo_dblib
@@ -1933,6 +1934,7 @@ Extensions:
--with-esoob=DIR Include Easysoft OOB support /usr/local/easysoft/oob/client
--with-unixODBC=DIR Include unixODBC support /usr/local
--with-dbmaker=DIR Include DBMaker support
+ --enable-opcache Enable Zend OPcache support
--enable-pcntl Enable pcntl support (CLI/CGI only)
--disable-pdo Disable PHP Data Objects support
--with-pdo-dblib=DIR PDO: DBLIB-DB support. DIR is the FreeTDS home directory
@@ -3684,7 +3686,7 @@ ac_config_headers="$ac_config_headers main/php_config.h"
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=5
PHP_RELEASE_VERSION=0
-PHP_EXTRA_VERSION="alpha6"
+PHP_EXTRA_VERSION="beta1"
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr $PHP_MAJOR_VERSION \* 10000 + $PHP_MINOR_VERSION \* 100 + $PHP_RELEASE_VERSION`
@@ -10801,6 +10803,66 @@ ext_output=$PHP_CLI
+for ac_func in setproctitle
+do :
+ ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle"
+if test "x$ac_cv_func_setproctitle" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SETPROCTITLE 1
+_ACEOF
+
+fi
+done
+
+
+for ac_header in sys/pstat.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/pstat.h" "ac_cv_header_sys_pstat_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_pstat_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_PSTAT_H 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PS_STRINGS" >&5
+$as_echo_n "checking for PS_STRINGS... " >&6; }
+if ${cli_cv_var_PS_STRINGS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <machine/vmparam.h>
+#include <sys/exec.h>
+
+int
+main ()
+{
+PS_STRINGS->ps_nargvstr = 1;
+PS_STRINGS->ps_argvstr = "foo";
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ cli_cv_var_PS_STRINGS=yes
+else
+ cli_cv_var_PS_STRINGS=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cli_cv_var_PS_STRINGS" >&5
+$as_echo "$cli_cv_var_PS_STRINGS" >&6; }
+if test "$cli_cv_var_PS_STRINGS" = yes ; then
+
+$as_echo "#define HAVE_PS_STRINGS /**/" >>confdefs.h
+
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CLI build" >&5
$as_echo_n "checking for CLI build... " >&6; }
if test "$PHP_CLI" != "no"; then
@@ -10884,7 +10946,7 @@ if test "$PHP_CLI" != "no"; then
old_IFS=$IFS
- for ac_src in php_cli.c php_http_parser.c php_cli_server.c; do
+ for ac_src in php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c; do
IFS=.
set $ac_src
@@ -67126,6 +67188,817 @@ fi
+php_enable_opcache=yes
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable Zend OPcache support" >&5
+$as_echo_n "checking whether to enable Zend OPcache support... " >&6; }
+# Check whether --enable-opcache was given.
+if test "${enable_opcache+set}" = set; then :
+ enableval=$enable_opcache; PHP_OPCACHE=$enableval
+else
+
+ PHP_OPCACHE=yes
+ test "$PHP_ENABLE_ALL" && PHP_OPCACHE=$PHP_ENABLE_ALL
+
+fi
+
+
+
+ext_output="yes, shared"
+ext_shared=yes
+case $PHP_OPCACHE in
+shared,*)
+ PHP_OPCACHE=`echo "$PHP_OPCACHE"|$SED 's/^shared,//'`
+ ;;
+shared)
+ PHP_OPCACHE=yes
+ ;;
+no)
+ ext_output=no
+ ext_shared=no
+ ;;
+*)
+ ext_output=yes
+ ext_shared=no
+ ;;
+esac
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ext_output" >&5
+$as_echo "$ext_output" >&6; }
+
+
+
+
+if test "$PHP_OPCACHE" != "no"; then
+
+ ac_fn_c_check_func "$LINENO" "mprotect" "ac_cv_func_mprotect"
+if test "x$ac_cv_func_mprotect" = xyes; then :
+
+
+$as_echo "#define HAVE_MPROTECT 1" >>confdefs.h
+
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysvipc shared memory support" >&5
+$as_echo_n "checking for sysvipc shared memory support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ msg=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <unistd.h>
+#include <string.h>
+
+int main() {
+ pid_t pid;
+ int status;
+ int ipc_id;
+ char *shm;
+ struct shmid_ds shmbuf;
+
+ ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W));
+ if (ipc_id == -1) {
+ return 1;
+ }
+
+ shm = shmat(ipc_id, NULL, 0);
+ if (shm == (void *)-1) {
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 2;
+ }
+
+ if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) {
+ shmdt(shm);
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 3;
+ }
+
+ shmbuf.shm_perm.uid = getuid();
+ shmbuf.shm_perm.gid = getgid();
+ shmbuf.shm_perm.mode = 0600;
+
+ if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) {
+ shmdt(shm);
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 4;
+ }
+
+ shmctl(ipc_id, IPC_RMID, NULL);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_SHM_IPC 1" >>confdefs.h
+
+ msg=yes
+else
+ msg=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mmap() using MAP_ANON shared memory support" >&5
+$as_echo_n "checking for mmap() using MAP_ANON shared memory support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ msg=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifndef MAP_ANON
+# ifdef MAP_ANONYMOUS
+# define MAP_ANON MAP_ANONYMOUS
+# endif
+#endif
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ char *shm;
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ if (shm == MAP_FAILED) {
+ return 1;
+ }
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_SHM_MMAP_ANON 1" >>confdefs.h
+
+ msg=yes
+else
+ msg=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mmap() using /dev/zero shared memory support" >&5
+$as_echo_n "checking for mmap() using /dev/zero shared memory support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ msg=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+
+ fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 1;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 2;
+ }
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_SHM_MMAP_ZERO 1" >>confdefs.h
+
+ msg=yes
+else
+ msg=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mmap() using shm_open() shared memory support" >&5
+$as_echo_n "checking for mmap() using shm_open() shared memory support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ msg=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+ char tmpname[4096];
+
+ sprintf(tmpname,"test.shm.%dXXXXXX", getpid());
+ if (mktemp(tmpname) == NULL) {
+ return 1;
+ }
+ fd = shm_open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 2;
+ }
+ if (ftruncate(fd, 4096) < 0) {
+ close(fd);
+ shm_unlink(tmpname);
+ return 3;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 4;
+ }
+ shm_unlink(tmpname);
+ close(fd);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_SHM_MMAP_POSIX 1" >>confdefs.h
+
+ msg=yes
+else
+ msg=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mmap() using regular file shared memory support" >&5
+$as_echo_n "checking for mmap() using regular file shared memory support... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ msg=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+ char tmpname[4096];
+
+ sprintf(tmpname,"test.shm.%dXXXXXX", getpid());
+ if (mktemp(tmpname) == NULL) {
+ return 1;
+ }
+ fd = open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 2;
+ }
+ if (ftruncate(fd, 4096) < 0) {
+ close(fd);
+ unlink(tmpname);
+ return 3;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 4;
+ }
+ unlink(tmpname);
+ close(fd);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_SHM_MMAP_FILE 1" >>confdefs.h
+
+ msg=yes
+else
+ msg=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+
+ ext_builddir=ext/opcache
+ ext_srcdir=$abs_srcdir/ext/opcache
+
+ ac_extra=
+
+ if test "shared" != "shared" && test "shared" != "yes" && test "" != "cli"; then
+ PHP_OPCACHE_SHARED=no
+
+
+ case ext/opcache in
+ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;;
+ /*) ac_srcdir=`echo "ext/opcache"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;;
+ *) ac_srcdir="$abs_srcdir/ext/opcache/"; ac_bdir="ext/opcache/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;;
+ esac
+
+
+
+ b_c_pre=$php_c_pre
+ b_cxx_pre=$php_cxx_pre
+ b_c_meta=$php_c_meta
+ b_cxx_meta=$php_cxx_meta
+ b_c_post=$php_c_post
+ b_cxx_post=$php_cxx_post
+ b_lo=$php_lo
+
+
+ old_IFS=$IFS
+ for ac_src in ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ zend_accelerator_util_funcs.c \
+ shared_alloc_shm.c \
+ shared_alloc_mmap.c \
+ shared_alloc_posix.c \
+ Optimizer/zend_optimizer.c; do
+
+ IFS=.
+ set $ac_src
+ ac_obj=$1
+ IFS=$old_IFS
+
+ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo"
+
+ case $ac_src in
+ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.s) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.S) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.cpp|*.cc|*.cxx) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;;
+ esac
+
+ cat >>Makefile.objects<<EOF
+$ac_bdir$ac_obj.lo: $ac_srcdir$ac_src
+ $ac_comp
+EOF
+ done
+
+
+ EXT_STATIC="$EXT_STATIC opcache"
+ if test "shared" != "nocli"; then
+ EXT_CLI_STATIC="$EXT_CLI_STATIC opcache"
+ fi
+ else
+ if test "shared" = "shared" || test "shared" = "yes"; then
+ PHP_OPCACHE_SHARED=yes
+
+ case ext/opcache in
+ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;;
+ /*) ac_srcdir=`echo "ext/opcache"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;;
+ *) ac_srcdir="$abs_srcdir/ext/opcache/"; ac_bdir="ext/opcache/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;;
+ esac
+
+
+
+ b_c_pre=$shared_c_pre
+ b_cxx_pre=$shared_cxx_pre
+ b_c_meta=$shared_c_meta
+ b_cxx_meta=$shared_cxx_meta
+ b_c_post=$shared_c_post
+ b_cxx_post=$shared_cxx_post
+ b_lo=$shared_lo
+
+
+ old_IFS=$IFS
+ for ac_src in ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ zend_accelerator_util_funcs.c \
+ shared_alloc_shm.c \
+ shared_alloc_mmap.c \
+ shared_alloc_posix.c \
+ Optimizer/zend_optimizer.c; do
+
+ IFS=.
+ set $ac_src
+ ac_obj=$1
+ IFS=$old_IFS
+
+ shared_objects_opcache="$shared_objects_opcache $ac_bdir$ac_obj.lo"
+
+ case $ac_src in
+ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.s) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.S) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.cpp|*.cc|*.cxx) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;;
+ esac
+
+ cat >>Makefile.objects<<EOF
+$ac_bdir$ac_obj.lo: $ac_srcdir$ac_src
+ $ac_comp
+EOF
+ done
+
+ case $host_alias in
+ *netware*)
+
+ install_modules="install-modules"
+
+ case $host_alias in
+ *aix*)
+ suffix=so
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -Wl,-G -o '$ext_builddir'/phpopcache.la -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) $(PHPOPCACHE_SHARED_LIBADD) && mv -f '$ext_builddir'/.libs/phpopcache.so '$ext_builddir'/phpopcache.so'
+ ;;
+ *netware*)
+ suffix=nlm
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -o $@ -shared -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) -L$(top_builddir)/netware -lphp5lib $(OPCACHE_SHARED_LIBADD)'
+ ;;
+ *)
+ suffix=la
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -o $@ -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) $(PHPOPCACHE_SHARED_LIBADD)'
+ ;;
+ esac
+
+ if test "xyes" = "xyes"; then
+ PHP_ZEND_EX="$PHP_ZEND_EX \$(phplibdir)/phpopcache.$suffix"
+ else
+ PHP_MODULES="$PHP_MODULES \$(phplibdir)/phpopcache.$suffix"
+ fi
+
+ PHP_VAR_SUBST="$PHP_VAR_SUBST shared_objects_opcache"
+
+ cat >>Makefile.objects<<EOF
+\$(phplibdir)/phpopcache.$suffix: $ext_builddir/phpopcache.$suffix
+ \$(LIBTOOL) --mode=install cp $ext_builddir/phpopcache.$suffix \$(phplibdir)
+
+$ext_builddir/phpopcache.$suffix: \$(shared_objects_opcache) \$(PHPOPCACHE_SHARED_DEPENDENCIES)
+ $link_cmd
+
+EOF
+
+ ;;
+ *)
+
+ install_modules="install-modules"
+
+ case $host_alias in
+ *aix*)
+ suffix=so
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -Wl,-G -o '$ext_builddir'/opcache.la -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) $(OPCACHE_SHARED_LIBADD) && mv -f '$ext_builddir'/.libs/opcache.so '$ext_builddir'/opcache.so'
+ ;;
+ *netware*)
+ suffix=nlm
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -o $@ -shared -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) -L$(top_builddir)/netware -lphp5lib $(ACHE_SHARED_LIBADD)'
+ ;;
+ *)
+ suffix=la
+ link_cmd='$(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -o $@ -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_opcache) $(OPCACHE_SHARED_LIBADD)'
+ ;;
+ esac
+
+ if test "xyes" = "xyes"; then
+ PHP_ZEND_EX="$PHP_ZEND_EX \$(phplibdir)/opcache.$suffix"
+ else
+ PHP_MODULES="$PHP_MODULES \$(phplibdir)/opcache.$suffix"
+ fi
+
+ PHP_VAR_SUBST="$PHP_VAR_SUBST shared_objects_opcache"
+
+ cat >>Makefile.objects<<EOF
+\$(phplibdir)/opcache.$suffix: $ext_builddir/opcache.$suffix
+ \$(LIBTOOL) --mode=install cp $ext_builddir/opcache.$suffix \$(phplibdir)
+
+$ext_builddir/opcache.$suffix: \$(shared_objects_opcache) \$(OPCACHE_SHARED_DEPENDENCIES)
+ $link_cmd
+
+EOF
+
+ ;;
+ esac
+
+cat >>confdefs.h <<_ACEOF
+#define COMPILE_DL_OPCACHE 1
+_ACEOF
+
+ fi
+ fi
+
+ if test "shared" != "shared" && test "shared" != "yes" && test "" = "cli"; then
+ PHP_OPCACHE_SHARED=no
+ case "$PHP_SAPI" in
+ cgi|embed)
+
+
+ case ext/opcache in
+ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;;
+ /*) ac_srcdir=`echo "ext/opcache"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;;
+ *) ac_srcdir="$abs_srcdir/ext/opcache/"; ac_bdir="ext/opcache/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;;
+ esac
+
+
+
+ b_c_pre=$php_c_pre
+ b_cxx_pre=$php_cxx_pre
+ b_c_meta=$php_c_meta
+ b_cxx_meta=$php_cxx_meta
+ b_c_post=$php_c_post
+ b_cxx_post=$php_cxx_post
+ b_lo=$php_lo
+
+
+ old_IFS=$IFS
+ for ac_src in ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ zend_accelerator_util_funcs.c \
+ shared_alloc_shm.c \
+ shared_alloc_mmap.c \
+ shared_alloc_posix.c \
+ Optimizer/zend_optimizer.c; do
+
+ IFS=.
+ set $ac_src
+ ac_obj=$1
+ IFS=$old_IFS
+
+ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo"
+
+ case $ac_src in
+ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.s) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.S) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.cpp|*.cc|*.cxx) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;;
+ esac
+
+ cat >>Makefile.objects<<EOF
+$ac_bdir$ac_obj.lo: $ac_srcdir$ac_src
+ $ac_comp
+EOF
+ done
+
+
+ EXT_STATIC="$EXT_STATIC opcache"
+ ;;
+ *)
+
+
+ case ext/opcache in
+ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;;
+ /*) ac_srcdir=`echo "ext/opcache"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;;
+ *) ac_srcdir="$abs_srcdir/ext/opcache/"; ac_bdir="ext/opcache/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;;
+ esac
+
+
+
+ b_c_pre=$php_c_pre
+ b_cxx_pre=$php_cxx_pre
+ b_c_meta=$php_c_meta
+ b_cxx_meta=$php_cxx_meta
+ b_c_post=$php_c_post
+ b_cxx_post=$php_cxx_post
+ b_lo=$php_lo
+
+
+ old_IFS=$IFS
+ for ac_src in ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ zend_accelerator_util_funcs.c \
+ shared_alloc_shm.c \
+ shared_alloc_mmap.c \
+ shared_alloc_posix.c \
+ Optimizer/zend_optimizer.c; do
+
+ IFS=.
+ set $ac_src
+ ac_obj=$1
+ IFS=$old_IFS
+
+ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo"
+
+ case $ac_src in
+ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.s) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.S) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;;
+ *.cpp|*.cc|*.cxx) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;;
+ esac
+
+ cat >>Makefile.objects<<EOF
+$ac_bdir$ac_obj.lo: $ac_srcdir$ac_src
+ $ac_comp
+EOF
+ done
+
+
+ ;;
+ esac
+ EXT_CLI_STATIC="$EXT_CLI_STATIC opcache"
+ fi
+
+
+ BUILD_DIR="$BUILD_DIR $ext_builddir"
+
+
+
+ if test "$ext_builddir" = "."; then
+ PHP_PECL_EXTENSION=opcache
+
+ PHP_VAR_SUBST="$PHP_VAR_SUBST PHP_PECL_EXTENSION"
+
+ fi
+
+
+
+
+ $php_shtool mkdir -p $ext_builddir/Optimizer
+
+
+fi
+
+
+
php_enable_pcntl=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable pcntl support" >&5
@@ -104780,7 +105653,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 104783 "configure"
+#line 105656 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -106692,7 +107565,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 106695 "configure"' > conftest.$ac_ext
+ echo '#line 107568 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -108084,7 +108957,7 @@ else
LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
cat > conftest.$ac_ext <<EOF
-#line 108087 "configure"
+#line 108960 "configure"
#include "confdefs.h"
int main() {
; return 0; }
@@ -108242,11 +109115,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"configure:108245: $lt_compile\"" >&5)
+ (eval echo "\"configure:109118: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "configure:108249: \$? = $ac_status" >&5
+ echo "configure:109122: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -108540,11 +109413,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"configure:108543: $lt_compile\"" >&5)
+ (eval echo "\"configure:109416: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "configure:108547: \$? = $ac_status" >&5
+ echo "configure:109420: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -108644,11 +109517,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"configure:108647: $lt_compile\"" >&5)
+ (eval echo "\"configure:109520: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "configure:108651: \$? = $ac_status" >&5
+ echo "configure:109524: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -109108,7 +109981,7 @@ _LT_EOF
# Determine the default libpath from the value encoded in an empty executable.
cat > conftest.$ac_ext <<EOF
-#line 109111 "configure"
+#line 109984 "configure"
#include "confdefs.h"
int main() {
; return 0; }
@@ -109150,7 +110023,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Determine the default libpath from the value encoded in an empty executable.
cat > conftest.$ac_ext <<EOF
-#line 109153 "configure"
+#line 110026 "configure"
#include "confdefs.h"
int main() {
; return 0; }
@@ -110675,7 +111548,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 110678 "configure"
+#line 111551 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -110775,7 +111648,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 110778 "configure"
+#line 111651 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -111840,7 +112713,7 @@ case $host_os in
# Determine the default libpath from the value encoded in an empty executable.
cat > conftest.$ac_ext <<EOF
-#line 111843 "configure"
+#line 112716 "configure"
#include "confdefs.h"
int main() {
; return 0; }
@@ -111883,7 +112756,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Determine the default libpath from the value encoded in an empty executable.
cat > conftest.$ac_ext <<EOF
-#line 111886 "configure"
+#line 112759 "configure"
#include "confdefs.h"
int main() {
; return 0; }
@@ -113135,11 +114008,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"configure:113138: $lt_compile\"" >&5)
+ (eval echo "\"configure:114011: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "configure:113142: \$? = $ac_status" >&5
+ echo "configure:114015: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -113239,11 +114112,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"configure:113242: $lt_compile\"" >&5)
+ (eval echo "\"configure:114115: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "configure:113246: \$? = $ac_status" >&5
+ echo "configure:114119: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
diff --git a/configure.in b/configure.in
index f0cb985ad..cc49903f8 100644
--- a/configure.in
+++ b/configure.in
@@ -120,7 +120,7 @@ int zend_sprintf(char *buffer, const char *format, ...);
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=5
PHP_RELEASE_VERSION=0
-PHP_EXTRA_VERSION="alpha6"
+PHP_EXTRA_VERSION="beta1"
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION`
diff --git a/ext/com_dotnet/com_iterator.c b/ext/com_dotnet/com_iterator.c
index ce4bdd67c..ecf395b16 100644
--- a/ext/com_dotnet/com_iterator.c
+++ b/ext/com_dotnet/com_iterator.c
@@ -74,16 +74,15 @@ static void com_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC
*data = &I->zdata;
}
-static int com_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
- ulong *int_key TSRMLS_DC)
+static void com_iter_get_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
if (I->key == (ulong)-1) {
- return HASH_KEY_NON_EXISTANT;
+ ZVAL_NULL(key);
+ } else {
+ ZVAL_LONG(key, I->key);
}
- *int_key = I->key;
- return HASH_KEY_IS_LONG;
}
static int com_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c
index ad9284974..5450370cd 100644
--- a/ext/com_dotnet/com_saproxy.c
+++ b/ext/com_dotnet/com_saproxy.c
@@ -519,16 +519,15 @@ static void saproxy_iter_get_data(zend_object_iterator *iter, zval ***data TSRML
*data = ptr_ptr;
}
-static int saproxy_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
- ulong *int_key TSRMLS_DC)
+static void saproxy_iter_get_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
if (I->key == -1) {
- return HASH_KEY_NON_EXISTANT;
+ ZVAL_NULL(key);
+ } else {
+ ZVAL_LONG(key, I->key);
}
- *int_key = (ulong)I->key;
- return HASH_KEY_IS_LONG;
}
static int saproxy_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
diff --git a/ext/date/lib/timezonedb.h b/ext/date/lib/timezonedb.h
index ba34c75b2..7bf9a9d22 100644
--- a/ext/date/lib/timezonedb.h
+++ b/ext/date/lib/timezonedb.h
@@ -14,573 +14,573 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[579] = {
{ "Africa/Bujumbura" , 0x000571 },
{ "Africa/Cairo" , 0x0005B5 },
{ "Africa/Casablanca" , 0x000878 },
- { "Africa/Ceuta" , 0x000A76 },
- { "Africa/Conakry" , 0x000D7D },
- { "Africa/Dakar" , 0x000DE8 },
- { "Africa/Dar_es_Salaam" , 0x000E4E },
- { "Africa/Djibouti" , 0x000EBB },
- { "Africa/Douala" , 0x000F10 },
- { "Africa/El_Aaiun" , 0x000F65 },
- { "Africa/Freetown" , 0x000FCB },
- { "Africa/Gaborone" , 0x0010DA },
- { "Africa/Harare" , 0x001147 },
- { "Africa/Johannesburg" , 0x00119C },
- { "Africa/Juba" , 0x00120A },
- { "Africa/Kampala" , 0x00131D },
- { "Africa/Khartoum" , 0x00139C },
- { "Africa/Kigali" , 0x0014AF },
- { "Africa/Kinshasa" , 0x001504 },
- { "Africa/Lagos" , 0x00155F },
- { "Africa/Libreville" , 0x0015B4 },
- { "Africa/Lome" , 0x001609 },
- { "Africa/Luanda" , 0x00164D },
- { "Africa/Lubumbashi" , 0x0016A2 },
- { "Africa/Lusaka" , 0x0016FD },
- { "Africa/Malabo" , 0x001752 },
- { "Africa/Maputo" , 0x0017B8 },
- { "Africa/Maseru" , 0x00180D },
- { "Africa/Mbabane" , 0x001875 },
- { "Africa/Mogadishu" , 0x0018CB },
- { "Africa/Monrovia" , 0x001926 },
- { "Africa/Nairobi" , 0x00198C },
- { "Africa/Ndjamena" , 0x001A0B },
- { "Africa/Niamey" , 0x001A77 },
- { "Africa/Nouakchott" , 0x001AEA },
- { "Africa/Ouagadougou" , 0x001B55 },
- { "Africa/Porto-Novo" , 0x001BAA },
- { "Africa/Sao_Tome" , 0x001C10 },
- { "Africa/Timbuktu" , 0x001C65 },
- { "Africa/Tripoli" , 0x001CD0 },
- { "Africa/Tunis" , 0x001EC9 },
- { "Africa/Windhoek" , 0x001FDB },
- { "America/Adak" , 0x002222 },
- { "America/Anchorage" , 0x002598 },
- { "America/Anguilla" , 0x00290C },
- { "America/Antigua" , 0x002961 },
- { "America/Araguaina" , 0x0029C7 },
- { "America/Argentina/Buenos_Aires" , 0x002C21 },
- { "America/Argentina/Catamarca" , 0x002DCF },
- { "America/Argentina/ComodRivadavia" , 0x002F90 },
- { "America/Argentina/Cordoba" , 0x003136 },
- { "America/Argentina/Jujuy" , 0x00330B },
- { "America/Argentina/La_Rioja" , 0x0034BF },
- { "America/Argentina/Mendoza" , 0x003677 },
- { "America/Argentina/Rio_Gallegos" , 0x003837 },
- { "America/Argentina/Salta" , 0x0039EC },
- { "America/Argentina/San_Juan" , 0x003B98 },
- { "America/Argentina/San_Luis" , 0x003D50 },
- { "America/Argentina/Tucuman" , 0x003F16 },
- { "America/Argentina/Ushuaia" , 0x0040D2 },
- { "America/Aruba" , 0x00428D },
- { "America/Asuncion" , 0x0042F3 },
- { "America/Atikokan" , 0x0045D8 },
- { "America/Atka" , 0x0046AE },
- { "America/Bahia" , 0x004A14 },
- { "America/Bahia_Banderas" , 0x004BA7 },
- { "America/Barbados" , 0x004E20 },
- { "America/Belem" , 0x004EBA },
- { "America/Belize" , 0x004FB5 },
- { "America/Blanc-Sablon" , 0x005131 },
- { "America/Boa_Vista" , 0x0051E5 },
- { "America/Bogota" , 0x0052EE },
- { "America/Boise" , 0x00535A },
- { "America/Buenos_Aires" , 0x0056F1 },
- { "America/Cambridge_Bay" , 0x00588A },
- { "America/Campo_Grande" , 0x005BB2 },
- { "America/Cancun" , 0x005EA1 },
- { "America/Caracas" , 0x0060E3 },
- { "America/Catamarca" , 0x00614A },
- { "America/Cayenne" , 0x0062F0 },
- { "America/Cayman" , 0x006352 },
- { "America/Chicago" , 0x0063A7 },
- { "America/Chihuahua" , 0x0068BE },
- { "America/Coral_Harbour" , 0x006B29 },
- { "America/Cordoba" , 0x006BBB },
- { "America/Costa_Rica" , 0x006D61 },
- { "America/Creston" , 0x006DEB },
- { "America/Cuiaba" , 0x006E77 },
- { "America/Curacao" , 0x007155 },
- { "America/Danmarkshavn" , 0x0071BB },
- { "America/Dawson" , 0x0072FF },
- { "America/Dawson_Creek" , 0x00761C },
- { "America/Denver" , 0x0077F6 },
- { "America/Detroit" , 0x007B7C },
- { "America/Dominica" , 0x007EDB },
- { "America/Edmonton" , 0x007F30 },
- { "America/Eirunepe" , 0x0082E8 },
- { "America/El_Salvador" , 0x0083FB },
- { "America/Ensenada" , 0x008470 },
- { "America/Fort_Wayne" , 0x008917 },
- { "America/Fortaleza" , 0x0087D9 },
- { "America/Glace_Bay" , 0x008B81 },
- { "America/Godthab" , 0x008EF8 },
- { "America/Goose_Bay" , 0x0091BC },
- { "America/Grand_Turk" , 0x009679 },
- { "America/Grenada" , 0x009928 },
- { "America/Guadeloupe" , 0x00997D },
- { "America/Guatemala" , 0x0099D2 },
- { "America/Guayaquil" , 0x009A5B },
- { "America/Guyana" , 0x009AB8 },
- { "America/Halifax" , 0x009B39 },
- { "America/Havana" , 0x00A04F },
- { "America/Hermosillo" , 0x00A3C2 },
- { "America/Indiana/Indianapolis" , 0x00A4A0 },
- { "America/Indiana/Knox" , 0x00A731 },
- { "America/Indiana/Marengo" , 0x00AAC8 },
- { "America/Indiana/Petersburg" , 0x00AD6E },
- { "America/Indiana/Tell_City" , 0x00B2BB },
- { "America/Indiana/Vevay" , 0x00B554 },
- { "America/Indiana/Vincennes" , 0x00B78F },
- { "America/Indiana/Winamac" , 0x00BA43 },
- { "America/Indianapolis" , 0x00B051 },
- { "America/Inuvik" , 0x00BCFC },
- { "America/Iqaluit" , 0x00BFF3 },
- { "America/Jamaica" , 0x00C315 },
- { "America/Jujuy" , 0x00C3DA },
- { "America/Juneau" , 0x00C584 },
- { "America/Kentucky/Louisville" , 0x00C902 },
- { "America/Kentucky/Monticello" , 0x00CD20 },
- { "America/Knox_IN" , 0x00D0A5 },
- { "America/Kralendijk" , 0x00D416 },
- { "America/La_Paz" , 0x00D47C },
- { "America/Lima" , 0x00D4E3 },
- { "America/Los_Angeles" , 0x00D58B },
- { "America/Louisville" , 0x00D99C },
- { "America/Lower_Princes" , 0x00DD91 },
- { "America/Maceio" , 0x00DDF7 },
- { "America/Managua" , 0x00DF31 },
- { "America/Manaus" , 0x00DFE4 },
- { "America/Marigot" , 0x00E0E6 },
- { "America/Martinique" , 0x00E13B },
- { "America/Matamoros" , 0x00E1A7 },
- { "America/Mazatlan" , 0x00E400 },
- { "America/Mendoza" , 0x00E66D },
- { "America/Menominee" , 0x00E821 },
- { "America/Merida" , 0x00EBA2 },
- { "America/Metlakatla" , 0x00EDDD },
- { "America/Mexico_City" , 0x00EF17 },
- { "America/Miquelon" , 0x00F192 },
- { "America/Moncton" , 0x00F404 },
- { "America/Monterrey" , 0x00F89B },
- { "America/Montevideo" , 0x00FAFE },
- { "America/Montreal" , 0x00FE10 },
- { "America/Montserrat" , 0x010326 },
- { "America/Nassau" , 0x01037B },
- { "America/New_York" , 0x0106C0 },
- { "America/Nipigon" , 0x010BCB },
- { "America/Nome" , 0x010F1C },
- { "America/Noronha" , 0x01129A },
- { "America/North_Dakota/Beulah" , 0x0113CA },
- { "America/North_Dakota/Center" , 0x01175E },
- { "America/North_Dakota/New_Salem" , 0x011AF2 },
- { "America/Ojinaga" , 0x011E9B },
- { "America/Panama" , 0x0120FC },
- { "America/Pangnirtung" , 0x012151 },
- { "America/Paramaribo" , 0x012487 },
- { "America/Phoenix" , 0x012519 },
- { "America/Port-au-Prince" , 0x0125C7 },
- { "America/Port_of_Spain" , 0x0127EC },
- { "America/Porto_Acre" , 0x0126ED },
- { "America/Porto_Velho" , 0x012841 },
- { "America/Puerto_Rico" , 0x012937 },
- { "America/Rainy_River" , 0x0129A2 },
- { "America/Rankin_Inlet" , 0x012CDA },
- { "America/Recife" , 0x012FC0 },
- { "America/Regina" , 0x0130EA },
- { "America/Resolute" , 0x0132A8 },
- { "America/Rio_Branco" , 0x013599 },
- { "America/Rosario" , 0x01369C },
- { "America/Santa_Isabel" , 0x013842 },
- { "America/Santarem" , 0x013BE5 },
- { "America/Santiago" , 0x013CEA },
- { "America/Santo_Domingo" , 0x014093 },
- { "America/Sao_Paulo" , 0x014159 },
- { "America/Scoresbysund" , 0x014468 },
- { "America/Shiprock" , 0x014756 },
- { "America/Sitka" , 0x014AE5 },
- { "America/St_Barthelemy" , 0x014E6D },
- { "America/St_Johns" , 0x014EC2 },
- { "America/St_Kitts" , 0x015415 },
- { "America/St_Lucia" , 0x01546A },
- { "America/St_Thomas" , 0x0154BF },
- { "America/St_Vincent" , 0x015514 },
- { "America/Swift_Current" , 0x015569 },
- { "America/Tegucigalpa" , 0x01568A },
- { "America/Thule" , 0x015709 },
- { "America/Thunder_Bay" , 0x015950 },
- { "America/Tijuana" , 0x015C99 },
- { "America/Toronto" , 0x016032 },
- { "America/Tortola" , 0x016549 },
- { "America/Vancouver" , 0x01659E },
- { "America/Virgin" , 0x0169DB },
- { "America/Whitehorse" , 0x016A30 },
- { "America/Winnipeg" , 0x016D4D },
- { "America/Yakutat" , 0x01718D },
- { "America/Yellowknife" , 0x0174F8 },
- { "Antarctica/Casey" , 0x017808 },
- { "Antarctica/Davis" , 0x0178A5 },
- { "Antarctica/DumontDUrville" , 0x017946 },
- { "Antarctica/Macquarie" , 0x0179D8 },
- { "Antarctica/Mawson" , 0x017C52 },
- { "Antarctica/McMurdo" , 0x017CCE },
- { "Antarctica/Palmer" , 0x017FD0 },
- { "Antarctica/Rothera" , 0x0182EC },
- { "Antarctica/South_Pole" , 0x018362 },
- { "Antarctica/Syowa" , 0x01866A },
- { "Antarctica/Vostok" , 0x0186D8 },
- { "Arctic/Longyearbyen" , 0x018749 },
- { "Asia/Aden" , 0x018A7B },
- { "Asia/Almaty" , 0x018AD0 },
- { "Asia/Amman" , 0x018C4F },
- { "Asia/Anadyr" , 0x018F05 },
- { "Asia/Aqtau" , 0x0190EA },
- { "Asia/Aqtobe" , 0x0192E9 },
- { "Asia/Ashgabat" , 0x0194A1 },
- { "Asia/Ashkhabad" , 0x0195BE },
- { "Asia/Baghdad" , 0x0196DB },
- { "Asia/Bahrain" , 0x019850 },
- { "Asia/Baku" , 0x0198B6 },
- { "Asia/Bangkok" , 0x019B9E },
- { "Asia/Beirut" , 0x019BF3 },
- { "Asia/Bishkek" , 0x019F00 },
- { "Asia/Brunei" , 0x01A0AC },
- { "Asia/Calcutta" , 0x01A10E },
- { "Asia/Choibalsan" , 0x01A187 },
- { "Asia/Chongqing" , 0x01A300 },
- { "Asia/Chungking" , 0x01A3EF },
- { "Asia/Colombo" , 0x01A49E },
- { "Asia/Dacca" , 0x01A53A },
- { "Asia/Damascus" , 0x01A5E0 },
- { "Asia/Dhaka" , 0x01A930 },
- { "Asia/Dili" , 0x01A9D6 },
- { "Asia/Dubai" , 0x01AA5F },
- { "Asia/Dushanbe" , 0x01AAB4 },
- { "Asia/Gaza" , 0x01ABB7 },
- { "Asia/Harbin" , 0x01AE10 },
- { "Asia/Hebron" , 0x01AEF7 },
- { "Asia/Ho_Chi_Minh" , 0x01B159 },
- { "Asia/Hong_Kong" , 0x01B1D1 },
- { "Asia/Hovd" , 0x01B393 },
- { "Asia/Irkutsk" , 0x01B50B },
- { "Asia/Istanbul" , 0x01B6F1 },
- { "Asia/Jakarta" , 0x01BADE },
- { "Asia/Jayapura" , 0x01BB88 },
- { "Asia/Jerusalem" , 0x01BC24 },
- { "Asia/Kabul" , 0x01BF53 },
- { "Asia/Kamchatka" , 0x01BFA4 },
- { "Asia/Karachi" , 0x01C180 },
- { "Asia/Kashgar" , 0x01C235 },
- { "Asia/Kathmandu" , 0x01C306 },
- { "Asia/Katmandu" , 0x01C36C },
- { "Asia/Khandyga" , 0x01C3D2 },
- { "Asia/Kolkata" , 0x01C5F7 },
- { "Asia/Krasnoyarsk" , 0x01C670 },
- { "Asia/Kuala_Lumpur" , 0x01C858 },
- { "Asia/Kuching" , 0x01C915 },
- { "Asia/Kuwait" , 0x01CA03 },
- { "Asia/Macao" , 0x01CA58 },
- { "Asia/Macau" , 0x01CB93 },
- { "Asia/Magadan" , 0x01CCCE },
- { "Asia/Makassar" , 0x01CEB0 },
- { "Asia/Manila" , 0x01CF74 },
- { "Asia/Muscat" , 0x01CFF9 },
- { "Asia/Nicosia" , 0x01D04E },
- { "Asia/Novokuznetsk" , 0x01D336 },
- { "Asia/Novosibirsk" , 0x01D538 },
- { "Asia/Omsk" , 0x01D723 },
- { "Asia/Oral" , 0x01D90A },
- { "Asia/Phnom_Penh" , 0x01DADA },
- { "Asia/Pontianak" , 0x01DB52 },
- { "Asia/Pyongyang" , 0x01DC13 },
- { "Asia/Qatar" , 0x01DC80 },
- { "Asia/Qyzylorda" , 0x01DCE6 },
- { "Asia/Rangoon" , 0x01DEBC },
- { "Asia/Riyadh" , 0x01DF34 },
- { "Asia/Saigon" , 0x01DF89 },
- { "Asia/Sakhalin" , 0x01E001 },
- { "Asia/Samarkand" , 0x01E1F8 },
- { "Asia/Seoul" , 0x01E32E },
- { "Asia/Shanghai" , 0x01E3D2 },
- { "Asia/Singapore" , 0x01E4B2 },
- { "Asia/Taipei" , 0x01E569 },
- { "Asia/Tashkent" , 0x01E681 },
- { "Asia/Tbilisi" , 0x01E7B2 },
- { "Asia/Tehran" , 0x01E96C },
- { "Asia/Tel_Aviv" , 0x01EBDA },
- { "Asia/Thimbu" , 0x01EF09 },
- { "Asia/Thimphu" , 0x01EF6F },
- { "Asia/Tokyo" , 0x01EFD5 },
- { "Asia/Ujung_Pandang" , 0x01F05E },
- { "Asia/Ulaanbaatar" , 0x01F0DA },
- { "Asia/Ulan_Bator" , 0x01F235 },
- { "Asia/Urumqi" , 0x01F382 },
- { "Asia/Ust-Nera" , 0x01F449 },
- { "Asia/Vientiane" , 0x01F64E },
- { "Asia/Vladivostok" , 0x01F6C6 },
- { "Asia/Yakutsk" , 0x01F8B2 },
- { "Asia/Yekaterinburg" , 0x01FA97 },
- { "Asia/Yerevan" , 0x01FCA2 },
- { "Atlantic/Azores" , 0x01FEA2 },
- { "Atlantic/Bermuda" , 0x0203A5 },
- { "Atlantic/Canary" , 0x020686 },
- { "Atlantic/Cape_Verde" , 0x02095C },
- { "Atlantic/Faeroe" , 0x0209D5 },
- { "Atlantic/Faroe" , 0x020C79 },
- { "Atlantic/Jan_Mayen" , 0x020F1D },
- { "Atlantic/Madeira" , 0x02124F },
- { "Atlantic/Reykjavik" , 0x021758 },
- { "Atlantic/South_Georgia" , 0x021911 },
- { "Atlantic/St_Helena" , 0x021B23 },
- { "Atlantic/Stanley" , 0x021955 },
- { "Australia/ACT" , 0x021B78 },
- { "Australia/Adelaide" , 0x021E95 },
- { "Australia/Brisbane" , 0x0221C1 },
- { "Australia/Broken_Hill" , 0x022288 },
- { "Australia/Canberra" , 0x0225C6 },
- { "Australia/Currie" , 0x0228E3 },
- { "Australia/Darwin" , 0x022C16 },
- { "Australia/Eucla" , 0x022C9C },
- { "Australia/Hobart" , 0x022D71 },
- { "Australia/LHI" , 0x0230CF },
- { "Australia/Lindeman" , 0x02336A },
- { "Australia/Lord_Howe" , 0x02344B },
- { "Australia/Melbourne" , 0x0236F6 },
- { "Australia/North" , 0x023A1B },
- { "Australia/NSW" , 0x023A8F },
- { "Australia/Perth" , 0x023DAC },
- { "Australia/Queensland" , 0x023E84 },
- { "Australia/South" , 0x023F30 },
- { "Australia/Sydney" , 0x02424D },
- { "Australia/Tasmania" , 0x02458A },
- { "Australia/Victoria" , 0x0248CF },
- { "Australia/West" , 0x024BEC },
- { "Australia/Yancowinna" , 0x024CA2 },
- { "Brazil/Acre" , 0x024FC4 },
- { "Brazil/DeNoronha" , 0x0250C3 },
- { "Brazil/East" , 0x0251E3 },
- { "Brazil/West" , 0x0254C0 },
- { "Canada/Atlantic" , 0x0255B8 },
- { "Canada/Central" , 0x025AA0 },
- { "Canada/East-Saskatchewan" , 0x0263AA },
- { "Canada/Eastern" , 0x025EBA },
- { "Canada/Mountain" , 0x026533 },
- { "Canada/Newfoundland" , 0x0268A9 },
- { "Canada/Pacific" , 0x026DD4 },
- { "Canada/Saskatchewan" , 0x0271ED },
- { "Canada/Yukon" , 0x027376 },
- { "CET" , 0x027679 },
- { "Chile/Continental" , 0x027982 },
- { "Chile/EasterIsland" , 0x027D1D },
- { "CST6CDT" , 0x02805F },
- { "Cuba" , 0x0283B0 },
- { "EET" , 0x028723 },
- { "Egypt" , 0x0289D6 },
- { "Eire" , 0x028C99 },
- { "EST" , 0x0291AA },
- { "EST5EDT" , 0x0291EE },
- { "Etc/GMT" , 0x02953F },
- { "Etc/GMT+0" , 0x02960B },
- { "Etc/GMT+1" , 0x029695 },
- { "Etc/GMT+10" , 0x029722 },
- { "Etc/GMT+11" , 0x0297B0 },
- { "Etc/GMT+12" , 0x02983E },
- { "Etc/GMT+2" , 0x029959 },
- { "Etc/GMT+3" , 0x0299E5 },
- { "Etc/GMT+4" , 0x029A71 },
- { "Etc/GMT+5" , 0x029AFD },
- { "Etc/GMT+6" , 0x029B89 },
- { "Etc/GMT+7" , 0x029C15 },
- { "Etc/GMT+8" , 0x029CA1 },
- { "Etc/GMT+9" , 0x029D2D },
- { "Etc/GMT-0" , 0x0295C7 },
- { "Etc/GMT-1" , 0x02964F },
- { "Etc/GMT-10" , 0x0296DB },
- { "Etc/GMT-11" , 0x029769 },
- { "Etc/GMT-12" , 0x0297F7 },
- { "Etc/GMT-13" , 0x029885 },
- { "Etc/GMT-14" , 0x0298CC },
- { "Etc/GMT-2" , 0x029913 },
- { "Etc/GMT-3" , 0x02999F },
- { "Etc/GMT-4" , 0x029A2B },
- { "Etc/GMT-5" , 0x029AB7 },
- { "Etc/GMT-6" , 0x029B43 },
- { "Etc/GMT-7" , 0x029BCF },
- { "Etc/GMT-8" , 0x029C5B },
- { "Etc/GMT-9" , 0x029CE7 },
- { "Etc/GMT0" , 0x029583 },
- { "Etc/Greenwich" , 0x029D73 },
- { "Etc/UCT" , 0x029DB7 },
- { "Etc/Universal" , 0x029DFB },
- { "Etc/UTC" , 0x029E3F },
- { "Etc/Zulu" , 0x029E83 },
- { "Europe/Amsterdam" , 0x029EC7 },
- { "Europe/Andorra" , 0x02A305 },
- { "Europe/Athens" , 0x02A581 },
- { "Europe/Belfast" , 0x02A8C4 },
- { "Europe/Belgrade" , 0x02ADFB },
- { "Europe/Berlin" , 0x02B0C4 },
- { "Europe/Bratislava" , 0x02B428 },
- { "Europe/Brussels" , 0x02B75A },
- { "Europe/Bucharest" , 0x02BB91 },
- { "Europe/Budapest" , 0x02BEBB },
- { "Europe/Busingen" , 0x02C22E },
- { "Europe/Chisinau" , 0x02C4E5 },
- { "Europe/Copenhagen" , 0x02C873 },
- { "Europe/Dublin" , 0x02CB7D },
- { "Europe/Gibraltar" , 0x02D08E },
- { "Europe/Guernsey" , 0x02D4E5 },
- { "Europe/Helsinki" , 0x02DA1C },
- { "Europe/Isle_of_Man" , 0x02DCD2 },
- { "Europe/Istanbul" , 0x02E209 },
- { "Europe/Jersey" , 0x02E5F6 },
- { "Europe/Kaliningrad" , 0x02EB2D },
- { "Europe/Kiev" , 0x02ED93 },
- { "Europe/Lisbon" , 0x02F0AA },
- { "Europe/Ljubljana" , 0x02F5AE },
- { "Europe/London" , 0x02F877 },
- { "Europe/Luxembourg" , 0x02FDAE },
- { "Europe/Madrid" , 0x030204 },
- { "Europe/Malta" , 0x0305CA },
- { "Europe/Mariehamn" , 0x030983 },
- { "Europe/Minsk" , 0x030C39 },
- { "Europe/Monaco" , 0x030E47 },
- { "Europe/Moscow" , 0x031282 },
- { "Europe/Nicosia" , 0x0314D3 },
- { "Europe/Oslo" , 0x0317BB },
- { "Europe/Paris" , 0x031AED },
- { "Europe/Podgorica" , 0x031F33 },
- { "Europe/Prague" , 0x0321FC },
- { "Europe/Riga" , 0x03252E },
- { "Europe/Rome" , 0x032873 },
- { "Europe/Samara" , 0x032C36 },
- { "Europe/San_Marino" , 0x032E69 },
- { "Europe/Sarajevo" , 0x03322C },
- { "Europe/Simferopol" , 0x0334F5 },
- { "Europe/Skopje" , 0x033820 },
- { "Europe/Sofia" , 0x033AE9 },
- { "Europe/Stockholm" , 0x033DF1 },
- { "Europe/Tallinn" , 0x0340A0 },
- { "Europe/Tirane" , 0x0343DA },
- { "Europe/Tiraspol" , 0x0346E0 },
- { "Europe/Uzhgorod" , 0x034A6E },
- { "Europe/Vaduz" , 0x034D85 },
- { "Europe/Vatican" , 0x035018 },
- { "Europe/Vienna" , 0x0353DB },
- { "Europe/Vilnius" , 0x035708 },
- { "Europe/Volgograd" , 0x035A47 },
- { "Europe/Warsaw" , 0x035C47 },
- { "Europe/Zagreb" , 0x036028 },
- { "Europe/Zaporozhye" , 0x0362F1 },
- { "Europe/Zurich" , 0x036632 },
- { "Factory" , 0x0368E1 },
- { "GB" , 0x036952 },
- { "GB-Eire" , 0x036E89 },
- { "GMT" , 0x0373C0 },
- { "GMT+0" , 0x03748C },
- { "GMT-0" , 0x037448 },
- { "GMT0" , 0x037404 },
- { "Greenwich" , 0x0374D0 },
- { "Hongkong" , 0x037514 },
- { "HST" , 0x0376D6 },
- { "Iceland" , 0x03771A },
- { "Indian/Antananarivo" , 0x0378D3 },
- { "Indian/Chagos" , 0x037947 },
- { "Indian/Christmas" , 0x0379A9 },
- { "Indian/Cocos" , 0x0379ED },
- { "Indian/Comoro" , 0x037A31 },
- { "Indian/Kerguelen" , 0x037A86 },
- { "Indian/Mahe" , 0x037ADB },
- { "Indian/Maldives" , 0x037B30 },
- { "Indian/Mauritius" , 0x037B85 },
- { "Indian/Mayotte" , 0x037BFB },
- { "Indian/Reunion" , 0x037C50 },
- { "Iran" , 0x037CA5 },
- { "Israel" , 0x037F13 },
- { "Jamaica" , 0x038242 },
- { "Japan" , 0x038307 },
- { "Kwajalein" , 0x038390 },
- { "Libya" , 0x0383F3 },
- { "MET" , 0x0385EC },
- { "Mexico/BajaNorte" , 0x0388F5 },
- { "Mexico/BajaSur" , 0x038C5E },
- { "Mexico/General" , 0x038EA3 },
- { "MST" , 0x039101 },
- { "MST7MDT" , 0x039145 },
- { "Navajo" , 0x039496 },
- { "NZ" , 0x03980F },
- { "NZ-CHAT" , 0x039B8D },
- { "Pacific/Apia" , 0x039E75 },
- { "Pacific/Auckland" , 0x03A011 },
- { "Pacific/Chatham" , 0x03A39D },
- { "Pacific/Chuuk" , 0x03A694 },
- { "Pacific/Easter" , 0x03A6ED },
- { "Pacific/Efate" , 0x03AA4B },
- { "Pacific/Enderbury" , 0x03AB11 },
- { "Pacific/Fakaofo" , 0x03AB7F },
- { "Pacific/Fiji" , 0x03ABD0 },
- { "Pacific/Funafuti" , 0x03AD63 },
- { "Pacific/Galapagos" , 0x03ADA7 },
- { "Pacific/Gambier" , 0x03AE1F },
- { "Pacific/Guadalcanal" , 0x03AE84 },
- { "Pacific/Guam" , 0x03AED9 },
- { "Pacific/Honolulu" , 0x03AF2F },
- { "Pacific/Johnston" , 0x03AFA6 },
- { "Pacific/Kiritimati" , 0x03AFF8 },
- { "Pacific/Kosrae" , 0x03B063 },
- { "Pacific/Kwajalein" , 0x03B0C0 },
- { "Pacific/Majuro" , 0x03B12C },
- { "Pacific/Marquesas" , 0x03B18B },
- { "Pacific/Midway" , 0x03B1F2 },
- { "Pacific/Nauru" , 0x03B27C },
- { "Pacific/Niue" , 0x03B2F4 },
- { "Pacific/Norfolk" , 0x03B352 },
- { "Pacific/Noumea" , 0x03B3A7 },
- { "Pacific/Pago_Pago" , 0x03B437 },
- { "Pacific/Palau" , 0x03B4C0 },
- { "Pacific/Pitcairn" , 0x03B504 },
- { "Pacific/Pohnpei" , 0x03B559 },
- { "Pacific/Ponape" , 0x03B5AE },
- { "Pacific/Port_Moresby" , 0x03B5F3 },
- { "Pacific/Rarotonga" , 0x03B637 },
- { "Pacific/Saipan" , 0x03B713 },
- { "Pacific/Samoa" , 0x03B776 },
- { "Pacific/Tahiti" , 0x03B7FF },
- { "Pacific/Tarawa" , 0x03B864 },
- { "Pacific/Tongatapu" , 0x03B8B8 },
- { "Pacific/Truk" , 0x03B944 },
- { "Pacific/Wake" , 0x03B989 },
- { "Pacific/Wallis" , 0x03B9D9 },
- { "Pacific/Yap" , 0x03BA1D },
- { "Poland" , 0x03BA62 },
- { "Portugal" , 0x03BE43 },
- { "PRC" , 0x03C33F },
- { "PST8PDT" , 0x03C3F0 },
- { "ROC" , 0x03C741 },
- { "ROK" , 0x03C859 },
- { "Singapore" , 0x03C8FD },
- { "Turkey" , 0x03C9B4 },
- { "UCT" , 0x03CDA1 },
- { "Universal" , 0x03CDE5 },
- { "US/Alaska" , 0x03CE29 },
- { "US/Aleutian" , 0x03D192 },
- { "US/Arizona" , 0x03D4F8 },
- { "US/Central" , 0x03D586 },
- { "US/East-Indiana" , 0x03DF90 },
- { "US/Eastern" , 0x03DA91 },
- { "US/Hawaii" , 0x03E1FA },
- { "US/Indiana-Starke" , 0x03E26B },
- { "US/Michigan" , 0x03E5DC },
- { "US/Mountain" , 0x03E913 },
- { "US/Pacific" , 0x03EC8C },
- { "US/Pacific-New" , 0x03F091 },
- { "US/Samoa" , 0x03F496 },
- { "UTC" , 0x03F51F },
- { "W-SU" , 0x03F816 },
- { "WET" , 0x03F563 },
- { "Zulu" , 0x03FA50 },
+ { "Africa/Ceuta" , 0x000ABC },
+ { "Africa/Conakry" , 0x000DC3 },
+ { "Africa/Dakar" , 0x000E2E },
+ { "Africa/Dar_es_Salaam" , 0x000E94 },
+ { "Africa/Djibouti" , 0x000F01 },
+ { "Africa/Douala" , 0x000F56 },
+ { "Africa/El_Aaiun" , 0x000FAB },
+ { "Africa/Freetown" , 0x001011 },
+ { "Africa/Gaborone" , 0x001120 },
+ { "Africa/Harare" , 0x00118D },
+ { "Africa/Johannesburg" , 0x0011E2 },
+ { "Africa/Juba" , 0x001250 },
+ { "Africa/Kampala" , 0x001363 },
+ { "Africa/Khartoum" , 0x0013E2 },
+ { "Africa/Kigali" , 0x0014F5 },
+ { "Africa/Kinshasa" , 0x00154A },
+ { "Africa/Lagos" , 0x0015A5 },
+ { "Africa/Libreville" , 0x0015FA },
+ { "Africa/Lome" , 0x00164F },
+ { "Africa/Luanda" , 0x001693 },
+ { "Africa/Lubumbashi" , 0x0016E8 },
+ { "Africa/Lusaka" , 0x001743 },
+ { "Africa/Malabo" , 0x001798 },
+ { "Africa/Maputo" , 0x0017FE },
+ { "Africa/Maseru" , 0x001853 },
+ { "Africa/Mbabane" , 0x0018BB },
+ { "Africa/Mogadishu" , 0x001911 },
+ { "Africa/Monrovia" , 0x00196C },
+ { "Africa/Nairobi" , 0x0019D2 },
+ { "Africa/Ndjamena" , 0x001A51 },
+ { "Africa/Niamey" , 0x001ABD },
+ { "Africa/Nouakchott" , 0x001B30 },
+ { "Africa/Ouagadougou" , 0x001B9B },
+ { "Africa/Porto-Novo" , 0x001BF0 },
+ { "Africa/Sao_Tome" , 0x001C56 },
+ { "Africa/Timbuktu" , 0x001CAB },
+ { "Africa/Tripoli" , 0x001D16 },
+ { "Africa/Tunis" , 0x001F0F },
+ { "Africa/Windhoek" , 0x002021 },
+ { "America/Adak" , 0x002268 },
+ { "America/Anchorage" , 0x0025DE },
+ { "America/Anguilla" , 0x002952 },
+ { "America/Antigua" , 0x0029A7 },
+ { "America/Araguaina" , 0x002A0D },
+ { "America/Argentina/Buenos_Aires" , 0x002C67 },
+ { "America/Argentina/Catamarca" , 0x002E15 },
+ { "America/Argentina/ComodRivadavia" , 0x002FD6 },
+ { "America/Argentina/Cordoba" , 0x00317C },
+ { "America/Argentina/Jujuy" , 0x003351 },
+ { "America/Argentina/La_Rioja" , 0x003505 },
+ { "America/Argentina/Mendoza" , 0x0036BD },
+ { "America/Argentina/Rio_Gallegos" , 0x00387D },
+ { "America/Argentina/Salta" , 0x003A32 },
+ { "America/Argentina/San_Juan" , 0x003BDE },
+ { "America/Argentina/San_Luis" , 0x003D96 },
+ { "America/Argentina/Tucuman" , 0x003F5C },
+ { "America/Argentina/Ushuaia" , 0x004118 },
+ { "America/Aruba" , 0x0042D3 },
+ { "America/Asuncion" , 0x004339 },
+ { "America/Atikokan" , 0x00461E },
+ { "America/Atka" , 0x0046F4 },
+ { "America/Bahia" , 0x004A5A },
+ { "America/Bahia_Banderas" , 0x004BED },
+ { "America/Barbados" , 0x004E66 },
+ { "America/Belem" , 0x004F00 },
+ { "America/Belize" , 0x004FFB },
+ { "America/Blanc-Sablon" , 0x005177 },
+ { "America/Boa_Vista" , 0x00522B },
+ { "America/Bogota" , 0x005334 },
+ { "America/Boise" , 0x0053A0 },
+ { "America/Buenos_Aires" , 0x005737 },
+ { "America/Cambridge_Bay" , 0x0058D0 },
+ { "America/Campo_Grande" , 0x005BF8 },
+ { "America/Cancun" , 0x005EE7 },
+ { "America/Caracas" , 0x006129 },
+ { "America/Catamarca" , 0x006190 },
+ { "America/Cayenne" , 0x006336 },
+ { "America/Cayman" , 0x006398 },
+ { "America/Chicago" , 0x0063ED },
+ { "America/Chihuahua" , 0x006904 },
+ { "America/Coral_Harbour" , 0x006B6F },
+ { "America/Cordoba" , 0x006C01 },
+ { "America/Costa_Rica" , 0x006DA7 },
+ { "America/Creston" , 0x006E31 },
+ { "America/Cuiaba" , 0x006EBD },
+ { "America/Curacao" , 0x00719B },
+ { "America/Danmarkshavn" , 0x007201 },
+ { "America/Dawson" , 0x007345 },
+ { "America/Dawson_Creek" , 0x007662 },
+ { "America/Denver" , 0x00783C },
+ { "America/Detroit" , 0x007BC2 },
+ { "America/Dominica" , 0x007F21 },
+ { "America/Edmonton" , 0x007F76 },
+ { "America/Eirunepe" , 0x00832E },
+ { "America/El_Salvador" , 0x008441 },
+ { "America/Ensenada" , 0x0084B6 },
+ { "America/Fort_Wayne" , 0x00895D },
+ { "America/Fortaleza" , 0x00881F },
+ { "America/Glace_Bay" , 0x008BC7 },
+ { "America/Godthab" , 0x008F3E },
+ { "America/Goose_Bay" , 0x009202 },
+ { "America/Grand_Turk" , 0x0096BF },
+ { "America/Grenada" , 0x00996E },
+ { "America/Guadeloupe" , 0x0099C3 },
+ { "America/Guatemala" , 0x009A18 },
+ { "America/Guayaquil" , 0x009AA1 },
+ { "America/Guyana" , 0x009AFE },
+ { "America/Halifax" , 0x009B7F },
+ { "America/Havana" , 0x00A095 },
+ { "America/Hermosillo" , 0x00A408 },
+ { "America/Indiana/Indianapolis" , 0x00A4E6 },
+ { "America/Indiana/Knox" , 0x00A777 },
+ { "America/Indiana/Marengo" , 0x00AB0E },
+ { "America/Indiana/Petersburg" , 0x00ADB4 },
+ { "America/Indiana/Tell_City" , 0x00B301 },
+ { "America/Indiana/Vevay" , 0x00B59A },
+ { "America/Indiana/Vincennes" , 0x00B7D5 },
+ { "America/Indiana/Winamac" , 0x00BA89 },
+ { "America/Indianapolis" , 0x00B097 },
+ { "America/Inuvik" , 0x00BD42 },
+ { "America/Iqaluit" , 0x00C039 },
+ { "America/Jamaica" , 0x00C35B },
+ { "America/Jujuy" , 0x00C420 },
+ { "America/Juneau" , 0x00C5CA },
+ { "America/Kentucky/Louisville" , 0x00C948 },
+ { "America/Kentucky/Monticello" , 0x00CD66 },
+ { "America/Knox_IN" , 0x00D0EB },
+ { "America/Kralendijk" , 0x00D45C },
+ { "America/La_Paz" , 0x00D4C2 },
+ { "America/Lima" , 0x00D529 },
+ { "America/Los_Angeles" , 0x00D5D1 },
+ { "America/Louisville" , 0x00D9E2 },
+ { "America/Lower_Princes" , 0x00DDD7 },
+ { "America/Maceio" , 0x00DE3D },
+ { "America/Managua" , 0x00DF77 },
+ { "America/Manaus" , 0x00E02A },
+ { "America/Marigot" , 0x00E12C },
+ { "America/Martinique" , 0x00E181 },
+ { "America/Matamoros" , 0x00E1ED },
+ { "America/Mazatlan" , 0x00E446 },
+ { "America/Mendoza" , 0x00E6B3 },
+ { "America/Menominee" , 0x00E867 },
+ { "America/Merida" , 0x00EBE8 },
+ { "America/Metlakatla" , 0x00EE23 },
+ { "America/Mexico_City" , 0x00EF5D },
+ { "America/Miquelon" , 0x00F1D8 },
+ { "America/Moncton" , 0x00F44A },
+ { "America/Monterrey" , 0x00F8E1 },
+ { "America/Montevideo" , 0x00FB44 },
+ { "America/Montreal" , 0x00FE56 },
+ { "America/Montserrat" , 0x01036C },
+ { "America/Nassau" , 0x0103C1 },
+ { "America/New_York" , 0x010706 },
+ { "America/Nipigon" , 0x010C11 },
+ { "America/Nome" , 0x010F62 },
+ { "America/Noronha" , 0x0112E0 },
+ { "America/North_Dakota/Beulah" , 0x011410 },
+ { "America/North_Dakota/Center" , 0x0117A4 },
+ { "America/North_Dakota/New_Salem" , 0x011B38 },
+ { "America/Ojinaga" , 0x011EE1 },
+ { "America/Panama" , 0x012142 },
+ { "America/Pangnirtung" , 0x012197 },
+ { "America/Paramaribo" , 0x0124CD },
+ { "America/Phoenix" , 0x01255F },
+ { "America/Port-au-Prince" , 0x01260D },
+ { "America/Port_of_Spain" , 0x01292C },
+ { "America/Porto_Acre" , 0x01282D },
+ { "America/Porto_Velho" , 0x012981 },
+ { "America/Puerto_Rico" , 0x012A77 },
+ { "America/Rainy_River" , 0x012AE2 },
+ { "America/Rankin_Inlet" , 0x012E1A },
+ { "America/Recife" , 0x013100 },
+ { "America/Regina" , 0x01322A },
+ { "America/Resolute" , 0x0133E8 },
+ { "America/Rio_Branco" , 0x0136D9 },
+ { "America/Rosario" , 0x0137DC },
+ { "America/Santa_Isabel" , 0x013982 },
+ { "America/Santarem" , 0x013D25 },
+ { "America/Santiago" , 0x013E2A },
+ { "America/Santo_Domingo" , 0x0141D3 },
+ { "America/Sao_Paulo" , 0x014299 },
+ { "America/Scoresbysund" , 0x0145A8 },
+ { "America/Shiprock" , 0x014896 },
+ { "America/Sitka" , 0x014C25 },
+ { "America/St_Barthelemy" , 0x014FAD },
+ { "America/St_Johns" , 0x015002 },
+ { "America/St_Kitts" , 0x015555 },
+ { "America/St_Lucia" , 0x0155AA },
+ { "America/St_Thomas" , 0x0155FF },
+ { "America/St_Vincent" , 0x015654 },
+ { "America/Swift_Current" , 0x0156A9 },
+ { "America/Tegucigalpa" , 0x0157CA },
+ { "America/Thule" , 0x015849 },
+ { "America/Thunder_Bay" , 0x015A90 },
+ { "America/Tijuana" , 0x015DD9 },
+ { "America/Toronto" , 0x016172 },
+ { "America/Tortola" , 0x016689 },
+ { "America/Vancouver" , 0x0166DE },
+ { "America/Virgin" , 0x016B1B },
+ { "America/Whitehorse" , 0x016B70 },
+ { "America/Winnipeg" , 0x016E8D },
+ { "America/Yakutat" , 0x0172CD },
+ { "America/Yellowknife" , 0x017638 },
+ { "Antarctica/Casey" , 0x017948 },
+ { "Antarctica/Davis" , 0x0179E5 },
+ { "Antarctica/DumontDUrville" , 0x017A86 },
+ { "Antarctica/Macquarie" , 0x017B18 },
+ { "Antarctica/Mawson" , 0x017D92 },
+ { "Antarctica/McMurdo" , 0x017E0E },
+ { "Antarctica/Palmer" , 0x018110 },
+ { "Antarctica/Rothera" , 0x01842C },
+ { "Antarctica/South_Pole" , 0x0184A2 },
+ { "Antarctica/Syowa" , 0x0187AA },
+ { "Antarctica/Vostok" , 0x018818 },
+ { "Arctic/Longyearbyen" , 0x018889 },
+ { "Asia/Aden" , 0x018BBB },
+ { "Asia/Almaty" , 0x018C10 },
+ { "Asia/Amman" , 0x018D8F },
+ { "Asia/Anadyr" , 0x019045 },
+ { "Asia/Aqtau" , 0x01922A },
+ { "Asia/Aqtobe" , 0x019429 },
+ { "Asia/Ashgabat" , 0x0195E1 },
+ { "Asia/Ashkhabad" , 0x0196FE },
+ { "Asia/Baghdad" , 0x01981B },
+ { "Asia/Bahrain" , 0x019990 },
+ { "Asia/Baku" , 0x0199F6 },
+ { "Asia/Bangkok" , 0x019CDE },
+ { "Asia/Beirut" , 0x019D33 },
+ { "Asia/Bishkek" , 0x01A040 },
+ { "Asia/Brunei" , 0x01A1EC },
+ { "Asia/Calcutta" , 0x01A24E },
+ { "Asia/Choibalsan" , 0x01A2C7 },
+ { "Asia/Chongqing" , 0x01A440 },
+ { "Asia/Chungking" , 0x01A52F },
+ { "Asia/Colombo" , 0x01A5DE },
+ { "Asia/Dacca" , 0x01A67A },
+ { "Asia/Damascus" , 0x01A720 },
+ { "Asia/Dhaka" , 0x01AA70 },
+ { "Asia/Dili" , 0x01AB16 },
+ { "Asia/Dubai" , 0x01AB9F },
+ { "Asia/Dushanbe" , 0x01ABF4 },
+ { "Asia/Gaza" , 0x01ACF7 },
+ { "Asia/Harbin" , 0x01AF50 },
+ { "Asia/Hebron" , 0x01B037 },
+ { "Asia/Ho_Chi_Minh" , 0x01B299 },
+ { "Asia/Hong_Kong" , 0x01B311 },
+ { "Asia/Hovd" , 0x01B4D3 },
+ { "Asia/Irkutsk" , 0x01B64B },
+ { "Asia/Istanbul" , 0x01B831 },
+ { "Asia/Jakarta" , 0x01BC1E },
+ { "Asia/Jayapura" , 0x01BCC8 },
+ { "Asia/Jerusalem" , 0x01BD64 },
+ { "Asia/Kabul" , 0x01C093 },
+ { "Asia/Kamchatka" , 0x01C0E4 },
+ { "Asia/Karachi" , 0x01C2C0 },
+ { "Asia/Kashgar" , 0x01C375 },
+ { "Asia/Kathmandu" , 0x01C446 },
+ { "Asia/Katmandu" , 0x01C4AC },
+ { "Asia/Khandyga" , 0x01C512 },
+ { "Asia/Kolkata" , 0x01C737 },
+ { "Asia/Krasnoyarsk" , 0x01C7B0 },
+ { "Asia/Kuala_Lumpur" , 0x01C998 },
+ { "Asia/Kuching" , 0x01CA55 },
+ { "Asia/Kuwait" , 0x01CB43 },
+ { "Asia/Macao" , 0x01CB98 },
+ { "Asia/Macau" , 0x01CCD3 },
+ { "Asia/Magadan" , 0x01CE0E },
+ { "Asia/Makassar" , 0x01CFF0 },
+ { "Asia/Manila" , 0x01D0B4 },
+ { "Asia/Muscat" , 0x01D139 },
+ { "Asia/Nicosia" , 0x01D18E },
+ { "Asia/Novokuznetsk" , 0x01D476 },
+ { "Asia/Novosibirsk" , 0x01D678 },
+ { "Asia/Omsk" , 0x01D863 },
+ { "Asia/Oral" , 0x01DA4A },
+ { "Asia/Phnom_Penh" , 0x01DC1A },
+ { "Asia/Pontianak" , 0x01DC92 },
+ { "Asia/Pyongyang" , 0x01DD53 },
+ { "Asia/Qatar" , 0x01DDC0 },
+ { "Asia/Qyzylorda" , 0x01DE26 },
+ { "Asia/Rangoon" , 0x01DFFC },
+ { "Asia/Riyadh" , 0x01E074 },
+ { "Asia/Saigon" , 0x01E0C9 },
+ { "Asia/Sakhalin" , 0x01E141 },
+ { "Asia/Samarkand" , 0x01E338 },
+ { "Asia/Seoul" , 0x01E46E },
+ { "Asia/Shanghai" , 0x01E512 },
+ { "Asia/Singapore" , 0x01E5F2 },
+ { "Asia/Taipei" , 0x01E6A9 },
+ { "Asia/Tashkent" , 0x01E7C1 },
+ { "Asia/Tbilisi" , 0x01E8F2 },
+ { "Asia/Tehran" , 0x01EAAC },
+ { "Asia/Tel_Aviv" , 0x01ED1A },
+ { "Asia/Thimbu" , 0x01F049 },
+ { "Asia/Thimphu" , 0x01F0AF },
+ { "Asia/Tokyo" , 0x01F115 },
+ { "Asia/Ujung_Pandang" , 0x01F19E },
+ { "Asia/Ulaanbaatar" , 0x01F21A },
+ { "Asia/Ulan_Bator" , 0x01F375 },
+ { "Asia/Urumqi" , 0x01F4C2 },
+ { "Asia/Ust-Nera" , 0x01F589 },
+ { "Asia/Vientiane" , 0x01F78E },
+ { "Asia/Vladivostok" , 0x01F806 },
+ { "Asia/Yakutsk" , 0x01F9F2 },
+ { "Asia/Yekaterinburg" , 0x01FBD7 },
+ { "Asia/Yerevan" , 0x01FDE2 },
+ { "Atlantic/Azores" , 0x01FFE2 },
+ { "Atlantic/Bermuda" , 0x0204E5 },
+ { "Atlantic/Canary" , 0x0207C6 },
+ { "Atlantic/Cape_Verde" , 0x020A9C },
+ { "Atlantic/Faeroe" , 0x020B15 },
+ { "Atlantic/Faroe" , 0x020DB9 },
+ { "Atlantic/Jan_Mayen" , 0x02105D },
+ { "Atlantic/Madeira" , 0x02138F },
+ { "Atlantic/Reykjavik" , 0x021898 },
+ { "Atlantic/South_Georgia" , 0x021A51 },
+ { "Atlantic/St_Helena" , 0x021C63 },
+ { "Atlantic/Stanley" , 0x021A95 },
+ { "Australia/ACT" , 0x021CB8 },
+ { "Australia/Adelaide" , 0x021FD5 },
+ { "Australia/Brisbane" , 0x022301 },
+ { "Australia/Broken_Hill" , 0x0223C8 },
+ { "Australia/Canberra" , 0x022706 },
+ { "Australia/Currie" , 0x022A23 },
+ { "Australia/Darwin" , 0x022D56 },
+ { "Australia/Eucla" , 0x022DDC },
+ { "Australia/Hobart" , 0x022EB1 },
+ { "Australia/LHI" , 0x02320F },
+ { "Australia/Lindeman" , 0x0234AA },
+ { "Australia/Lord_Howe" , 0x02358B },
+ { "Australia/Melbourne" , 0x023836 },
+ { "Australia/North" , 0x023B5B },
+ { "Australia/NSW" , 0x023BCF },
+ { "Australia/Perth" , 0x023EEC },
+ { "Australia/Queensland" , 0x023FC4 },
+ { "Australia/South" , 0x024070 },
+ { "Australia/Sydney" , 0x02438D },
+ { "Australia/Tasmania" , 0x0246CA },
+ { "Australia/Victoria" , 0x024A0F },
+ { "Australia/West" , 0x024D2C },
+ { "Australia/Yancowinna" , 0x024DE2 },
+ { "Brazil/Acre" , 0x025104 },
+ { "Brazil/DeNoronha" , 0x025203 },
+ { "Brazil/East" , 0x025323 },
+ { "Brazil/West" , 0x025600 },
+ { "Canada/Atlantic" , 0x0256F8 },
+ { "Canada/Central" , 0x025BE0 },
+ { "Canada/East-Saskatchewan" , 0x0264EA },
+ { "Canada/Eastern" , 0x025FFA },
+ { "Canada/Mountain" , 0x026673 },
+ { "Canada/Newfoundland" , 0x0269E9 },
+ { "Canada/Pacific" , 0x026F14 },
+ { "Canada/Saskatchewan" , 0x02732D },
+ { "Canada/Yukon" , 0x0274B6 },
+ { "CET" , 0x0277B9 },
+ { "Chile/Continental" , 0x027AC2 },
+ { "Chile/EasterIsland" , 0x027E5D },
+ { "CST6CDT" , 0x02819F },
+ { "Cuba" , 0x0284F0 },
+ { "EET" , 0x028863 },
+ { "Egypt" , 0x028B16 },
+ { "Eire" , 0x028DD9 },
+ { "EST" , 0x0292EA },
+ { "EST5EDT" , 0x02932E },
+ { "Etc/GMT" , 0x02967F },
+ { "Etc/GMT+0" , 0x02974B },
+ { "Etc/GMT+1" , 0x0297D5 },
+ { "Etc/GMT+10" , 0x029862 },
+ { "Etc/GMT+11" , 0x0298F0 },
+ { "Etc/GMT+12" , 0x02997E },
+ { "Etc/GMT+2" , 0x029A99 },
+ { "Etc/GMT+3" , 0x029B25 },
+ { "Etc/GMT+4" , 0x029BB1 },
+ { "Etc/GMT+5" , 0x029C3D },
+ { "Etc/GMT+6" , 0x029CC9 },
+ { "Etc/GMT+7" , 0x029D55 },
+ { "Etc/GMT+8" , 0x029DE1 },
+ { "Etc/GMT+9" , 0x029E6D },
+ { "Etc/GMT-0" , 0x029707 },
+ { "Etc/GMT-1" , 0x02978F },
+ { "Etc/GMT-10" , 0x02981B },
+ { "Etc/GMT-11" , 0x0298A9 },
+ { "Etc/GMT-12" , 0x029937 },
+ { "Etc/GMT-13" , 0x0299C5 },
+ { "Etc/GMT-14" , 0x029A0C },
+ { "Etc/GMT-2" , 0x029A53 },
+ { "Etc/GMT-3" , 0x029ADF },
+ { "Etc/GMT-4" , 0x029B6B },
+ { "Etc/GMT-5" , 0x029BF7 },
+ { "Etc/GMT-6" , 0x029C83 },
+ { "Etc/GMT-7" , 0x029D0F },
+ { "Etc/GMT-8" , 0x029D9B },
+ { "Etc/GMT-9" , 0x029E27 },
+ { "Etc/GMT0" , 0x0296C3 },
+ { "Etc/Greenwich" , 0x029EB3 },
+ { "Etc/UCT" , 0x029EF7 },
+ { "Etc/Universal" , 0x029F3B },
+ { "Etc/UTC" , 0x029F7F },
+ { "Etc/Zulu" , 0x029FC3 },
+ { "Europe/Amsterdam" , 0x02A007 },
+ { "Europe/Andorra" , 0x02A445 },
+ { "Europe/Athens" , 0x02A6C1 },
+ { "Europe/Belfast" , 0x02AA04 },
+ { "Europe/Belgrade" , 0x02AF3B },
+ { "Europe/Berlin" , 0x02B204 },
+ { "Europe/Bratislava" , 0x02B568 },
+ { "Europe/Brussels" , 0x02B89A },
+ { "Europe/Bucharest" , 0x02BCD1 },
+ { "Europe/Budapest" , 0x02BFFB },
+ { "Europe/Busingen" , 0x02C36E },
+ { "Europe/Chisinau" , 0x02C625 },
+ { "Europe/Copenhagen" , 0x02C9B3 },
+ { "Europe/Dublin" , 0x02CCBD },
+ { "Europe/Gibraltar" , 0x02D1CE },
+ { "Europe/Guernsey" , 0x02D625 },
+ { "Europe/Helsinki" , 0x02DB5C },
+ { "Europe/Isle_of_Man" , 0x02DE12 },
+ { "Europe/Istanbul" , 0x02E349 },
+ { "Europe/Jersey" , 0x02E736 },
+ { "Europe/Kaliningrad" , 0x02EC6D },
+ { "Europe/Kiev" , 0x02EED3 },
+ { "Europe/Lisbon" , 0x02F1EA },
+ { "Europe/Ljubljana" , 0x02F6EE },
+ { "Europe/London" , 0x02F9B7 },
+ { "Europe/Luxembourg" , 0x02FEEE },
+ { "Europe/Madrid" , 0x030344 },
+ { "Europe/Malta" , 0x03070A },
+ { "Europe/Mariehamn" , 0x030AC3 },
+ { "Europe/Minsk" , 0x030D79 },
+ { "Europe/Monaco" , 0x030F87 },
+ { "Europe/Moscow" , 0x0313C2 },
+ { "Europe/Nicosia" , 0x031613 },
+ { "Europe/Oslo" , 0x0318FB },
+ { "Europe/Paris" , 0x031C2D },
+ { "Europe/Podgorica" , 0x032073 },
+ { "Europe/Prague" , 0x03233C },
+ { "Europe/Riga" , 0x03266E },
+ { "Europe/Rome" , 0x0329B3 },
+ { "Europe/Samara" , 0x032D76 },
+ { "Europe/San_Marino" , 0x032FA9 },
+ { "Europe/Sarajevo" , 0x03336C },
+ { "Europe/Simferopol" , 0x033635 },
+ { "Europe/Skopje" , 0x033960 },
+ { "Europe/Sofia" , 0x033C29 },
+ { "Europe/Stockholm" , 0x033F31 },
+ { "Europe/Tallinn" , 0x0341E0 },
+ { "Europe/Tirane" , 0x03451A },
+ { "Europe/Tiraspol" , 0x034820 },
+ { "Europe/Uzhgorod" , 0x034BAE },
+ { "Europe/Vaduz" , 0x034EC5 },
+ { "Europe/Vatican" , 0x035158 },
+ { "Europe/Vienna" , 0x03551B },
+ { "Europe/Vilnius" , 0x035848 },
+ { "Europe/Volgograd" , 0x035B87 },
+ { "Europe/Warsaw" , 0x035D87 },
+ { "Europe/Zagreb" , 0x036168 },
+ { "Europe/Zaporozhye" , 0x036431 },
+ { "Europe/Zurich" , 0x036772 },
+ { "Factory" , 0x036A21 },
+ { "GB" , 0x036A92 },
+ { "GB-Eire" , 0x036FC9 },
+ { "GMT" , 0x037500 },
+ { "GMT+0" , 0x0375CC },
+ { "GMT-0" , 0x037588 },
+ { "GMT0" , 0x037544 },
+ { "Greenwich" , 0x037610 },
+ { "Hongkong" , 0x037654 },
+ { "HST" , 0x037816 },
+ { "Iceland" , 0x03785A },
+ { "Indian/Antananarivo" , 0x037A13 },
+ { "Indian/Chagos" , 0x037A87 },
+ { "Indian/Christmas" , 0x037AE9 },
+ { "Indian/Cocos" , 0x037B2D },
+ { "Indian/Comoro" , 0x037B71 },
+ { "Indian/Kerguelen" , 0x037BC6 },
+ { "Indian/Mahe" , 0x037C1B },
+ { "Indian/Maldives" , 0x037C70 },
+ { "Indian/Mauritius" , 0x037CC5 },
+ { "Indian/Mayotte" , 0x037D3B },
+ { "Indian/Reunion" , 0x037D90 },
+ { "Iran" , 0x037DE5 },
+ { "Israel" , 0x038053 },
+ { "Jamaica" , 0x038382 },
+ { "Japan" , 0x038447 },
+ { "Kwajalein" , 0x0384D0 },
+ { "Libya" , 0x038533 },
+ { "MET" , 0x03872C },
+ { "Mexico/BajaNorte" , 0x038A35 },
+ { "Mexico/BajaSur" , 0x038D9E },
+ { "Mexico/General" , 0x038FE3 },
+ { "MST" , 0x039241 },
+ { "MST7MDT" , 0x039285 },
+ { "Navajo" , 0x0395D6 },
+ { "NZ" , 0x03994F },
+ { "NZ-CHAT" , 0x039CCD },
+ { "Pacific/Apia" , 0x039FB5 },
+ { "Pacific/Auckland" , 0x03A151 },
+ { "Pacific/Chatham" , 0x03A4DD },
+ { "Pacific/Chuuk" , 0x03A7D4 },
+ { "Pacific/Easter" , 0x03A82D },
+ { "Pacific/Efate" , 0x03AB8B },
+ { "Pacific/Enderbury" , 0x03AC51 },
+ { "Pacific/Fakaofo" , 0x03ACBF },
+ { "Pacific/Fiji" , 0x03AD10 },
+ { "Pacific/Funafuti" , 0x03AEA3 },
+ { "Pacific/Galapagos" , 0x03AEE7 },
+ { "Pacific/Gambier" , 0x03AF5F },
+ { "Pacific/Guadalcanal" , 0x03AFC4 },
+ { "Pacific/Guam" , 0x03B019 },
+ { "Pacific/Honolulu" , 0x03B06F },
+ { "Pacific/Johnston" , 0x03B0E6 },
+ { "Pacific/Kiritimati" , 0x03B138 },
+ { "Pacific/Kosrae" , 0x03B1A3 },
+ { "Pacific/Kwajalein" , 0x03B200 },
+ { "Pacific/Majuro" , 0x03B26C },
+ { "Pacific/Marquesas" , 0x03B2CB },
+ { "Pacific/Midway" , 0x03B332 },
+ { "Pacific/Nauru" , 0x03B3BC },
+ { "Pacific/Niue" , 0x03B434 },
+ { "Pacific/Norfolk" , 0x03B492 },
+ { "Pacific/Noumea" , 0x03B4E7 },
+ { "Pacific/Pago_Pago" , 0x03B577 },
+ { "Pacific/Palau" , 0x03B600 },
+ { "Pacific/Pitcairn" , 0x03B644 },
+ { "Pacific/Pohnpei" , 0x03B699 },
+ { "Pacific/Ponape" , 0x03B6EE },
+ { "Pacific/Port_Moresby" , 0x03B733 },
+ { "Pacific/Rarotonga" , 0x03B777 },
+ { "Pacific/Saipan" , 0x03B853 },
+ { "Pacific/Samoa" , 0x03B8B6 },
+ { "Pacific/Tahiti" , 0x03B93F },
+ { "Pacific/Tarawa" , 0x03B9A4 },
+ { "Pacific/Tongatapu" , 0x03B9F8 },
+ { "Pacific/Truk" , 0x03BA84 },
+ { "Pacific/Wake" , 0x03BAC9 },
+ { "Pacific/Wallis" , 0x03BB19 },
+ { "Pacific/Yap" , 0x03BB5D },
+ { "Poland" , 0x03BBA2 },
+ { "Portugal" , 0x03BF83 },
+ { "PRC" , 0x03C47F },
+ { "PST8PDT" , 0x03C530 },
+ { "ROC" , 0x03C881 },
+ { "ROK" , 0x03C999 },
+ { "Singapore" , 0x03CA3D },
+ { "Turkey" , 0x03CAF4 },
+ { "UCT" , 0x03CEE1 },
+ { "Universal" , 0x03CF25 },
+ { "US/Alaska" , 0x03CF69 },
+ { "US/Aleutian" , 0x03D2D2 },
+ { "US/Arizona" , 0x03D638 },
+ { "US/Central" , 0x03D6C6 },
+ { "US/East-Indiana" , 0x03E0D0 },
+ { "US/Eastern" , 0x03DBD1 },
+ { "US/Hawaii" , 0x03E33A },
+ { "US/Indiana-Starke" , 0x03E3AB },
+ { "US/Michigan" , 0x03E71C },
+ { "US/Mountain" , 0x03EA53 },
+ { "US/Pacific" , 0x03EDCC },
+ { "US/Pacific-New" , 0x03F1D1 },
+ { "US/Samoa" , 0x03F5D6 },
+ { "UTC" , 0x03F65F },
+ { "W-SU" , 0x03F956 },
+ { "WET" , 0x03F6A3 },
+ { "Zulu" , 0x03FB90 },
};
/* This is a generated file, do not modify */
-const unsigned char timelib_timezone_db_data_builtin[260756] = {
+const unsigned char timelib_timezone_db_data_builtin[261076] = {
/* Africa/Abidjan */
@@ -758,7 +758,7 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
/* Africa/Casablanca */
0x50, 0x48, 0x50, 0x31, 0x01, 0x4D, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x96, 0x51, 0xF9, 0x9C,
+0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x96, 0x51, 0xF9, 0x9C,
0xC6, 0xFF, 0x14, 0x80, 0xC7, 0x58, 0xAC, 0x70, 0xC7, 0xD9, 0xED, 0x80, 0xD2, 0xA1, 0x32, 0xF0,
0xDB, 0x35, 0xA4, 0x00, 0xDB, 0xEE, 0x27, 0xF0, 0xFB, 0x25, 0x72, 0x40, 0xFB, 0xC2, 0xEF, 0x70,
0x08, 0x6B, 0x84, 0x80, 0x08, 0xC6, 0x6D, 0xF0, 0x0B, 0xE8, 0x0C, 0x00, 0x0C, 0x61, 0x47, 0xF0,
@@ -766,28 +766,33 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
0x1A, 0xB7, 0xA6, 0x00, 0x1E, 0x18, 0x6F, 0xF0, 0x48, 0x41, 0xE6, 0x80, 0x48, 0xBB, 0x22, 0x70,
0x4A, 0x23, 0x1A, 0x00, 0x4A, 0x8D, 0xD5, 0x70, 0x4B, 0xDC, 0xC0, 0x80, 0x4C, 0x5D, 0xE5, 0x70,
0x4D, 0x97, 0xB8, 0x80, 0x4E, 0x34, 0x8C, 0xF0, 0x4F, 0x9C, 0xA0, 0xA0, 0x50, 0x08, 0xBB, 0xA0,
-0x50, 0x31, 0x9A, 0x20, 0x50, 0x67, 0xA7, 0xA0, 0x51, 0x7C, 0x82, 0xA0, 0x52, 0x47, 0x89, 0xA0,
-0x53, 0x5C, 0x64, 0xA0, 0x54, 0x27, 0x6B, 0xA0, 0x55, 0x3C, 0x46, 0xA0, 0x56, 0x07, 0x4D, 0xA0,
-0x57, 0x1C, 0x28, 0xA0, 0x57, 0xE7, 0x2F, 0xA0, 0x59, 0x05, 0x45, 0x20, 0x59, 0xC7, 0x11, 0xA0,
-0x5A, 0xE5, 0x27, 0x20, 0x5B, 0xB0, 0x2E, 0x20, 0x5C, 0xC5, 0x09, 0x20, 0x5D, 0x90, 0x10, 0x20,
-0x5E, 0xA4, 0xEB, 0x20, 0x5F, 0x6F, 0xF2, 0x20, 0x60, 0x84, 0xCD, 0x20, 0x61, 0x4F, 0xD4, 0x20,
-0x62, 0x64, 0xAF, 0x20, 0x63, 0x2F, 0xB6, 0x20, 0x64, 0x4D, 0xCB, 0xA0, 0x65, 0x0F, 0x98, 0x20,
-0x66, 0x2D, 0xAD, 0xA0, 0x66, 0xF8, 0xB4, 0xA0, 0x68, 0x0D, 0x8F, 0xA0, 0x68, 0xD8, 0x96, 0xA0,
-0x69, 0xED, 0x71, 0xA0, 0x6A, 0xB8, 0x78, 0xA0, 0x6B, 0xCD, 0x53, 0xA0, 0x6C, 0x98, 0x5A, 0xA0,
-0x6D, 0xB6, 0x70, 0x20, 0x6E, 0x78, 0x3C, 0xA0, 0x6F, 0x96, 0x52, 0x20, 0x70, 0x61, 0x59, 0x20,
-0x71, 0x76, 0x34, 0x20, 0x72, 0x41, 0x3B, 0x20, 0x73, 0x56, 0x16, 0x20, 0x74, 0x21, 0x1D, 0x20,
-0x75, 0x35, 0xF8, 0x20, 0x76, 0x00, 0xFF, 0x20, 0x77, 0x15, 0xDA, 0x20, 0x77, 0xE0, 0xE1, 0x20,
-0x78, 0xFE, 0xF6, 0xA0, 0x79, 0xC0, 0xC3, 0x20, 0x7A, 0xDE, 0xD8, 0xA0, 0x7B, 0xA9, 0xDF, 0xA0,
-0x7C, 0xBE, 0xBA, 0xA0, 0x7D, 0x89, 0xC1, 0xA0, 0x7E, 0x9E, 0x9C, 0xA0, 0x7F, 0x69, 0xA3, 0xA0,
+0x50, 0x31, 0x9A, 0x20, 0x50, 0x67, 0xA7, 0xA0, 0x51, 0x7C, 0x82, 0xA0, 0x51, 0xDB, 0x6E, 0xA0,
+0x52, 0x02, 0xFB, 0xA0, 0x52, 0x47, 0x89, 0xA0, 0x53, 0x5C, 0x64, 0xA0, 0x53, 0xAF, 0x73, 0x20,
+0x53, 0xD7, 0x00, 0x20, 0x54, 0x27, 0x6B, 0xA0, 0x55, 0x3C, 0x46, 0xA0, 0x55, 0x82, 0x26, 0x20,
+0x55, 0xA9, 0xB3, 0x20, 0x56, 0x07, 0x4D, 0xA0, 0x57, 0x1C, 0x28, 0xA0, 0x57, 0x56, 0x2A, 0xA0,
+0x57, 0x7D, 0xB7, 0xA0, 0x57, 0xE7, 0x2F, 0xA0, 0x59, 0x05, 0x45, 0x20, 0x59, 0x28, 0xDD, 0xA0,
+0x59, 0x50, 0x6A, 0xA0, 0x59, 0xC7, 0x11, 0xA0, 0x5A, 0xE5, 0x27, 0x20, 0x5A, 0xFB, 0x90, 0xA0,
+0x5B, 0x23, 0x1D, 0xA0, 0x5B, 0xB0, 0x2E, 0x20, 0x5C, 0xC5, 0x09, 0x20, 0x5C, 0xCF, 0x95, 0x20,
+0x5C, 0xF7, 0x22, 0x20, 0x5D, 0x90, 0x10, 0x20, 0x5E, 0xC9, 0xD5, 0x20, 0x5F, 0x6F, 0xF2, 0x20,
+0x60, 0x9C, 0x88, 0x20, 0x61, 0x4F, 0xD4, 0x20, 0x62, 0x70, 0x8C, 0xA0, 0x63, 0x2F, 0xB6, 0x20,
+0x64, 0x4D, 0xCB, 0xA0, 0x65, 0x0F, 0x98, 0x20, 0x66, 0x2D, 0xAD, 0xA0, 0x66, 0xF8, 0xB4, 0xA0,
+0x68, 0x0D, 0x8F, 0xA0, 0x68, 0xD8, 0x96, 0xA0, 0x69, 0xED, 0x71, 0xA0, 0x6A, 0xB8, 0x78, 0xA0,
+0x6B, 0xCD, 0x53, 0xA0, 0x6C, 0x98, 0x5A, 0xA0, 0x6D, 0xB6, 0x70, 0x20, 0x6E, 0x78, 0x3C, 0xA0,
+0x6F, 0x96, 0x52, 0x20, 0x70, 0x61, 0x59, 0x20, 0x71, 0x76, 0x34, 0x20, 0x72, 0x41, 0x3B, 0x20,
+0x73, 0x56, 0x16, 0x20, 0x74, 0x21, 0x1D, 0x20, 0x75, 0x35, 0xF8, 0x20, 0x76, 0x00, 0xFF, 0x20,
+0x77, 0x15, 0xDA, 0x20, 0x77, 0xE0, 0xE1, 0x20, 0x78, 0xFE, 0xF6, 0xA0, 0x79, 0xC0, 0xC3, 0x20,
+0x7A, 0xDE, 0xD8, 0xA0, 0x7B, 0xA9, 0xDF, 0xA0, 0x7C, 0xBE, 0xBA, 0xA0, 0x7D, 0x89, 0xC1, 0xA0,
+0x7E, 0x9E, 0x9C, 0xA0, 0x7F, 0x69, 0xA3, 0xA0, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
-0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
-0x02, 0xFF, 0xFF, 0xF8, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x10, 0x01, 0x04, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x09, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x0D, 0x4C, 0x4D, 0x54, 0x00, 0x57, 0x45, 0x53,
-0x54, 0x00, 0x57, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xBC, 0xAC, 0xC8, 0x01, 0x07, 0x16, 0x42, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0xFF, 0xFF, 0xF8, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x0E,
+0x10, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x0D, 0x4C,
+0x4D, 0x54, 0x00, 0x57, 0x45, 0x53, 0x54, 0x00, 0x57, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xAC, 0xC8, 0x01, 0x07, 0x16, 0x42,
+0x00, 0x00, 0x00, 0x00,
/* Africa/Ceuta */
0x50, 0x48, 0x50, 0x31, 0x01, 0x45, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1863,7 +1868,7 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
0x45, 0x31, 0xB2, 0x40, 0x45, 0xF3, 0x70, 0xB0, 0x47, 0x1A, 0xCE, 0xC0, 0x47, 0xD3, 0x52, 0xB0,
0x48, 0xFA, 0xB0, 0xC0, 0x49, 0xB3, 0x34, 0xB0, 0x4A, 0xDA, 0x92, 0xC0, 0x4B, 0xC1, 0x3B, 0x30,
0x4C, 0xA7, 0xFF, 0xC0, 0x4D, 0xA1, 0x1D, 0x30, 0x4E, 0x87, 0xE1, 0xC0, 0x4F, 0x80, 0xFF, 0x30,
-0x50, 0x70, 0xFE, 0x40, 0x51, 0x6A, 0x1B, 0xB0, 0x52, 0x50, 0xE0, 0x40, 0x53, 0x49, 0xFD, 0xB0,
+0x50, 0x70, 0xFE, 0x40, 0x51, 0x4E, 0x6C, 0x30, 0x52, 0x50, 0xE0, 0x40, 0x53, 0x49, 0xFD, 0xB0,
0x54, 0x30, 0xC2, 0x40, 0x55, 0x29, 0xDF, 0xB0, 0x56, 0x10, 0xA4, 0x40, 0x57, 0x09, 0xC1, 0xB0,
0x57, 0xF0, 0x86, 0x40, 0x58, 0xE9, 0xA3, 0xB0, 0x59, 0xD0, 0x68, 0x40, 0x5A, 0xC9, 0x85, 0xB0,
0x5B, 0xB9, 0x84, 0xC0, 0x5C, 0xB2, 0xA2, 0x30, 0x5D, 0x99, 0x66, 0xC0, 0x5E, 0x92, 0x84, 0x30,
@@ -5743,7 +5748,7 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
/* America/Port-au-Prince */
0x50, 0x48, 0x50, 0x31, 0x01, 0x48, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0D, 0x9C, 0x6E, 0x71, 0xFC,
+0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0D, 0x9C, 0x6E, 0x71, 0xFC,
0x19, 0x1B, 0x46, 0xD0, 0x1A, 0x01, 0xEF, 0x40, 0x1A, 0xF1, 0xEE, 0x50, 0x1B, 0xE1, 0xD1, 0x40,
0x1C, 0xD1, 0xD0, 0x50, 0x1D, 0xC1, 0xB3, 0x40, 0x1E, 0xB1, 0xB2, 0x50, 0x1F, 0xA1, 0x95, 0x40,
0x20, 0x91, 0x94, 0x50, 0x21, 0x81, 0x77, 0x40, 0x22, 0x55, 0xD4, 0xE0, 0x23, 0x6A, 0xAF, 0xE0,
@@ -5753,13 +5758,29 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
0x2F, 0x7E, 0x3D, 0x60, 0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x59, 0xE0, 0x32, 0x72, 0xFA, 0x60,
0x33, 0x47, 0x3B, 0xE0, 0x34, 0x52, 0xDC, 0x60, 0x42, 0x4F, 0x78, 0x50, 0x43, 0x64, 0x45, 0x40,
0x44, 0x2F, 0x5A, 0x50, 0x45, 0x44, 0x27, 0x40, 0x4F, 0x5C, 0x4D, 0x70, 0x50, 0x96, 0x04, 0x60,
-0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03,
-0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x01,
-0x02, 0x01, 0x02, 0x01, 0x02, 0xFF, 0xFF, 0xBC, 0x44, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0xC0, 0x01,
-0x05, 0xFF, 0xFF, 0xB9, 0xB0, 0x00, 0x09, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x05, 0xFF, 0xFF, 0xB9,
-0xB0, 0x00, 0x09, 0x50, 0x50, 0x4D, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00,
-0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x9B, 0xD5, 0x00, 0xA4,
-0x49, 0x4A, 0x00, 0x00, 0x00, 0x00,
+0x51, 0x3C, 0x2F, 0x70, 0x52, 0x75, 0xE6, 0x60, 0x53, 0x1C, 0x11, 0x70, 0x54, 0x55, 0xC8, 0x60,
+0x54, 0xFB, 0xF3, 0x70, 0x56, 0x35, 0xAA, 0x60, 0x56, 0xE5, 0x0F, 0xF0, 0x58, 0x1E, 0xC6, 0xE0,
+0x58, 0xC4, 0xF1, 0xF0, 0x59, 0xFE, 0xA8, 0xE0, 0x5A, 0xA4, 0xD3, 0xF0, 0x5B, 0xDE, 0x8A, 0xE0,
+0x5C, 0x84, 0xB5, 0xF0, 0x5D, 0xBE, 0x6C, 0xE0, 0x5E, 0x64, 0x97, 0xF0, 0x5F, 0x9E, 0x4E, 0xE0,
+0x60, 0x4D, 0xB4, 0x70, 0x61, 0x87, 0x6B, 0x60, 0x62, 0x2D, 0x96, 0x70, 0x63, 0x67, 0x4D, 0x60,
+0x64, 0x0D, 0x78, 0x70, 0x65, 0x47, 0x2F, 0x60, 0x65, 0xED, 0x5A, 0x70, 0x67, 0x27, 0x11, 0x60,
+0x67, 0xCD, 0x3C, 0x70, 0x69, 0x06, 0xF3, 0x60, 0x69, 0xAD, 0x1E, 0x70, 0x6A, 0xE6, 0xD5, 0x60,
+0x6B, 0x96, 0x3A, 0xF0, 0x6C, 0xCF, 0xF1, 0xE0, 0x6D, 0x76, 0x1C, 0xF0, 0x6E, 0xAF, 0xD3, 0xE0,
+0x6F, 0x55, 0xFE, 0xF0, 0x70, 0x8F, 0xB5, 0xE0, 0x71, 0x35, 0xE0, 0xF0, 0x72, 0x6F, 0x97, 0xE0,
+0x73, 0x15, 0xC2, 0xF0, 0x74, 0x4F, 0x79, 0xE0, 0x74, 0xFE, 0xDF, 0x70, 0x76, 0x38, 0x96, 0x60,
+0x76, 0xDE, 0xC1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xBE, 0xA3, 0x70, 0x79, 0xF8, 0x5A, 0x60,
+0x7A, 0x9E, 0x85, 0x70, 0x7B, 0xD8, 0x3C, 0x60, 0x7C, 0x7E, 0x67, 0x70, 0x7D, 0xB8, 0x1E, 0x60,
+0x7E, 0x5E, 0x49, 0x70, 0x7F, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+0x02, 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0xFF,
+0xFF, 0xBC, 0x44, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x05, 0xFF, 0xFF, 0xB9, 0xB0, 0x00,
+0x09, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x05, 0xFF, 0xFF, 0xB9, 0xB0, 0x00, 0x09, 0x50, 0x50, 0x4D,
+0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x9B, 0xD5, 0x00, 0xA4, 0x49, 0x4A, 0x00, 0x00, 0x00, 0x00,
+
/* America/Porto_Acre */
0x50, 0x48, 0x50, 0x31, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -18361,4 +18382,4 @@ const unsigned char timelib_timezone_db_data_builtin[260756] = {
0x00, 0x00, 0x55, 0x54, 0x43, 0x00, 0x00, 0x00, 0x00, 0x89, 0x54, 0x40, 0x01, 0x12, 0xA8, 0x80,
0x00, 0x00, 0x00, 0x00, };
-const timelib_tzdb timezonedb_builtin = { "2013.1", 579, timezonedb_idx_builtin, timelib_timezone_db_data_builtin };
+const timelib_tzdb timezonedb_builtin = { "2013.2", 579, timezonedb_idx_builtin, timelib_timezone_db_data_builtin };
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index 71958578d..a073aa691 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -39,6 +39,20 @@ static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i
static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; }
#endif
+#ifdef PHP_WIN32
+#define DATE_I64_BUF_LEN 65
+# define DATE_I64A(i, s, len) _i64toa_s(i, s, len, 10)
+# define DATE_A64I(i, s) i = _atoi64(s)
+#else
+#define DATE_I64_BUF_LEN 65
+# define DATE_I64A(i, s, len) \
+ do { \
+ int st = snprintf(s, len, "%lld", i); \
+ s[st] = '\0'; \
+ } while (0);
+# define DATE_A64I(i, s) i = atoll(s)
+#endif
+
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
ZEND_ARG_INFO(0, format)
@@ -488,6 +502,8 @@ const zend_function_entry date_funcs_interval[] = {
const zend_function_entry date_funcs_period[] = {
PHP_ME(DatePeriod, __construct, arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
+ PHP_ME(DatePeriod, __wakeup, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(DatePeriod, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_FE_END
};
@@ -594,9 +610,13 @@ static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_
static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC);
static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC);
+static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC);
+static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC);
zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC);
void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC);
+static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC);
+static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC);
/* {{{ Module struct */
zend_module_entry date_module_entry = {
@@ -1867,11 +1887,10 @@ static void date_period_it_current_data(zend_object_iterator *iter, zval ***data
/* {{{ date_period_it_current_key */
-static int date_period_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+static void date_period_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
- date_period_it *iterator = (date_period_it *)iter;
- *int_key = iterator->current_index;
- return HASH_KEY_IS_LONG;
+ date_period_it *iterator = (date_period_it *)iter;
+ ZVAL_LONG(key, iterator->current_index);
}
/* }}} */
@@ -2013,6 +2032,11 @@ static void date_register_classes(TSRMLS_D)
zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable);
memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
date_object_handlers_period.clone_obj = date_object_clone_period;
+ date_object_handlers_period.get_properties = date_object_get_properties_period;
+ date_object_handlers_period.get_property_ptr_ptr = NULL;
+ date_object_handlers_period.get_gc = date_object_get_gc_period;
+ date_object_handlers_period.read_property = date_period_read_property;
+ date_object_handlers_period.write_property = date_period_write_property;
#define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC);
@@ -2125,7 +2149,7 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
props = zend_std_get_properties(object TSRMLS_CC);
- if (!dateobj->time) {
+ if (!dateobj->time || GC_G(gc_active)) {
return props;
}
@@ -2273,7 +2297,6 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
zval *zv;
php_interval_obj *intervalobj;
-
intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
props = zend_std_get_properties(object TSRMLS_CC);
@@ -2282,6 +2305,15 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
return props;
}
+#define PHP_DATE_INTERVAL_ADD_PROPERTY_I64(n, f) \
+ do { \
+ char i64_buf[DATE_I64_BUF_LEN]; \
+ MAKE_STD_ZVAL(zv); \
+ DATE_I64A(intervalobj->diff->f, i64_buf, DATE_I64_BUF_LEN); \
+ ZVAL_STRING(zv, i64_buf, 1); \
+ zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL); \
+ } while(0);
+
#define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
MAKE_STD_ZVAL(zv); \
ZVAL_LONG(zv, intervalobj->diff->f); \
@@ -2293,14 +2325,21 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
+ PHP_DATE_INTERVAL_ADD_PROPERTY("weekday", weekday);
+ PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior);
+ PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of);
PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
if (intervalobj->diff->days != -99999) {
- PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
+ PHP_DATE_INTERVAL_ADD_PROPERTY_I64("days", days);
} else {
MAKE_STD_ZVAL(zv);
ZVAL_FALSE(zv);
zend_hash_update(props, "days", 5, &zv, sizeof(zval), NULL);
}
+ PHP_DATE_INTERVAL_ADD_PROPERTY("special_type", special.type);
+ PHP_DATE_INTERVAL_ADD_PROPERTY_I64("special_amount", special.amount);
+ PHP_DATE_INTERVAL_ADD_PROPERTY("have_weekday_relative", have_weekday_relative);
+ PHP_DATE_INTERVAL_ADD_PROPERTY("have_special_relative", have_special_relative);
return props;
}
@@ -2402,6 +2441,7 @@ PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
object_init_ex(object, pce);
Z_SET_REFCOUNT_P(object, 1);
Z_UNSET_ISREF_P(object);
+
return object;
}
@@ -2634,13 +2674,15 @@ static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dat
case TIMELIB_ZONETYPE_OFFSET:
case TIMELIB_ZONETYPE_ABBR: {
char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2);
+ int ret;
snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone));
- php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
+ ret = php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
efree(tmp);
- return 1;
+ return 1 == ret;
}
- case TIMELIB_ZONETYPE_ID:
+ case TIMELIB_ZONETYPE_ID: {
+ int ret;
convert_to_string(*z_timezone);
tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC);
@@ -2651,9 +2693,10 @@ static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dat
tzobj->tzi.tz = tzi;
tzobj->initialized = 1;
- php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
+ ret = php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
zval_ptr_dtor(&tmp_obj);
- return 1;
+ return 1 == ret;
+ }
}
}
}
@@ -2677,7 +2720,9 @@ PHP_METHOD(DateTime, __set_state)
php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
- php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
+ if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
+ php_error(E_ERROR, "Invalid serialization data for DateTime object");
+ }
}
/* }}} */
@@ -2697,7 +2742,9 @@ PHP_METHOD(DateTimeImmutable, __set_state)
php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC);
dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
- php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
+ if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
+ php_error(E_ERROR, "Invalid serialization data for DateTimeImmutable object");
+ }
}
/* }}} */
@@ -2713,7 +2760,9 @@ PHP_METHOD(DateTime, __wakeup)
myht = Z_OBJPROP_P(object);
- php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
+ if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
+ php_error(E_ERROR, "Invalid serialization data for DateTime object");
+ }
}
/* }}} */
@@ -3952,30 +4001,48 @@ PHP_METHOD(DateInterval, __construct)
}
/* }}} */
-static long php_date_long_from_hash_element(HashTable *myht, char *element, size_t size)
-{
- zval **z_arg = NULL;
-
- if (zend_hash_find(myht, element, size + 1, (void**) &z_arg) == SUCCESS) {
- convert_to_long(*z_arg);
- return Z_LVAL_PP(z_arg);
- } else {
- return -1;
- }
-}
static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht TSRMLS_DC)
{
(*intobj)->diff = timelib_rel_time_ctor();
- (*intobj)->diff->y = php_date_long_from_hash_element(myht, "y", 1);
- (*intobj)->diff->m = php_date_long_from_hash_element(myht, "m", 1);
- (*intobj)->diff->d = php_date_long_from_hash_element(myht, "d", 1);
- (*intobj)->diff->h = php_date_long_from_hash_element(myht, "h", 1);
- (*intobj)->diff->i = php_date_long_from_hash_element(myht, "i", 1);
- (*intobj)->diff->s = php_date_long_from_hash_element(myht, "s", 1);
- (*intobj)->diff->invert = php_date_long_from_hash_element(myht, "invert", 6);
- (*intobj)->diff->days = php_date_long_from_hash_element(myht, "days", 4);
+#define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \
+ do { \
+ zval **z_arg = NULL; \
+ if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
+ convert_to_long(*z_arg); \
+ (*intobj)->diff->member = (itype)Z_LVAL_PP(z_arg); \
+ } else { \
+ (*intobj)->diff->member = (itype)def; \
+ } \
+ } while (0);
+
+#define PHP_DATE_INTERVAL_READ_PROPERTY_I64(element, member) \
+ do { \
+ zval **z_arg = NULL; \
+ if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
+ convert_to_string(*z_arg); \
+ DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \
+ } else { \
+ (*intobj)->diff->member = -1LL; \
+ } \
+ } while (0);
+
+ PHP_DATE_INTERVAL_READ_PROPERTY("y", y, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("m", m, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("d", d, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("h", h, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("weekday_behavior", weekday_behavior, int, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("first_last_day_of", first_last_day_of, int, -1)
+ PHP_DATE_INTERVAL_READ_PROPERTY("invert", invert, int, 0);
+ PHP_DATE_INTERVAL_READ_PROPERTY_I64("days", days);
+ PHP_DATE_INTERVAL_READ_PROPERTY("special_type", special.type, unsigned int, 0);
+ PHP_DATE_INTERVAL_READ_PROPERTY_I64("special_amount", special.amount);
+ PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0);
+ PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0);
(*intobj)->initialized = 1;
return 0;
@@ -4581,6 +4648,230 @@ PHP_FUNCTION(date_sun_info)
timelib_time_dtor(t2);
}
/* }}} */
+
+static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC)
+{
+ *table = NULL;
+ *n = 0;
+ return zend_std_get_properties(object TSRMLS_CC);
+}
+
+static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC)
+{
+ HashTable *props;
+ zval *zv;
+ php_period_obj *period_obj;
+
+ period_obj = zend_object_store_get_object(object TSRMLS_CC);
+
+ props = zend_std_get_properties(object TSRMLS_CC);
+
+ if (!period_obj->start || GC_G(gc_active)) {
+ return props;
+ }
+
+ MAKE_STD_ZVAL(zv);
+ if (period_obj->start) {
+ php_date_obj *date_obj;
+ object_init_ex(zv, date_ce_date);
+ date_obj = zend_object_store_get_object(zv TSRMLS_CC);
+ date_obj->time = timelib_time_clone(period_obj->start);
+ } else {
+ ZVAL_NULL(zv);
+ }
+ zend_hash_update(props, "start", sizeof("start"), &zv, sizeof(zv), NULL);
+
+ MAKE_STD_ZVAL(zv);
+ if (period_obj->current) {
+ php_date_obj *date_obj;
+ object_init_ex(zv, date_ce_date);
+ date_obj = zend_object_store_get_object(zv TSRMLS_CC);
+ date_obj->time = timelib_time_clone(period_obj->current);
+ } else {
+ ZVAL_NULL(zv);
+ }
+ zend_hash_update(props, "current", sizeof("current"), &zv, sizeof(zv), NULL);
+
+ MAKE_STD_ZVAL(zv);
+ if (period_obj->end) {
+ php_date_obj *date_obj;
+ object_init_ex(zv, date_ce_date);
+ date_obj = zend_object_store_get_object(zv TSRMLS_CC);
+ date_obj->time = timelib_time_clone(period_obj->end);
+ } else {
+ ZVAL_NULL(zv);
+ }
+ zend_hash_update(props, "end", sizeof("end"), &zv, sizeof(zv), NULL);
+
+ MAKE_STD_ZVAL(zv);
+ if (period_obj->interval) {
+ php_interval_obj *interval_obj;
+ object_init_ex(zv, date_ce_interval);
+ interval_obj = zend_object_store_get_object(zv TSRMLS_CC);
+ interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
+ interval_obj->initialized = 1;
+ } else {
+ ZVAL_NULL(zv);
+ }
+ zend_hash_update(props, "interval", sizeof("interval"), &zv, sizeof(zv), NULL);
+
+ /* converted to larger type (int->long); must check when unserializing */
+ MAKE_STD_ZVAL(zv);
+ ZVAL_LONG(zv, (long) period_obj->recurrences);
+ zend_hash_update(props, "recurrences", sizeof("recurrences"), &zv, sizeof(zv), NULL);
+
+ MAKE_STD_ZVAL(zv);
+ ZVAL_BOOL(zv, period_obj->include_start_date);
+ zend_hash_update(props, "include_start_date", sizeof("include_start_date"), &zv, sizeof(zv), NULL);
+
+ return props;
+}
+
+static int php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht TSRMLS_DC)
+{
+ zval **ht_entry;
+
+ /* this function does no rollback on error */
+
+ if (zend_hash_find(myht, "start", sizeof("start"), (void**) &ht_entry) == SUCCESS) {
+ if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
+ php_date_obj *date_obj;
+ date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
+ period_obj->start = timelib_time_clone(date_obj->time);
+ period_obj->start_ce = Z_OBJCE_PP(ht_entry);
+ } else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (zend_hash_find(myht, "end", sizeof("end"), (void**) &ht_entry) == SUCCESS) {
+ if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
+ php_date_obj *date_obj;
+ date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
+ period_obj->end = timelib_time_clone(date_obj->time);
+ } else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (zend_hash_find(myht, "current", sizeof("current"), (void**) &ht_entry) == SUCCESS) {
+ if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
+ php_date_obj *date_obj;
+ date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
+ period_obj->current = timelib_time_clone(date_obj->time);
+ } else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (zend_hash_find(myht, "interval", sizeof("interval"), (void**) &ht_entry) == SUCCESS) {
+ if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_interval) {
+ php_interval_obj *interval_obj;
+ interval_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
+ period_obj->interval = timelib_rel_time_clone(interval_obj->diff);
+ } else { /* interval is required */
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (zend_hash_find(myht, "recurrences", sizeof("recurrences"), (void**) &ht_entry) == SUCCESS &&
+ Z_TYPE_PP(ht_entry) == IS_LONG && Z_LVAL_PP(ht_entry) >= 0 && Z_LVAL_PP(ht_entry) <= INT_MAX) {
+ period_obj->recurrences = Z_LVAL_PP(ht_entry);
+ } else {
+ return 0;
+ }
+
+ if (zend_hash_find(myht, "include_start_date", sizeof("include_start_date"), (void**) &ht_entry) == SUCCESS &&
+ Z_TYPE_PP(ht_entry) == IS_BOOL) {
+ period_obj->include_start_date = Z_BVAL_PP(ht_entry);
+ } else {
+ return 0;
+ }
+
+ period_obj->initialized = 1;
+
+ return 1;
+}
+
+/* {{{ proto DatePeriod::__set_state()
+*/
+PHP_METHOD(DatePeriod, __set_state)
+{
+ php_period_obj *period_obj;
+ zval *array;
+ HashTable *myht;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ myht = Z_ARRVAL_P(array);
+
+ object_init_ex(return_value, date_ce_period);
+ period_obj = zend_object_store_get_object(return_value TSRMLS_CC);
+ if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
+ php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
+ }
+}
+/* }}} */
+
+/* {{{ proto DatePeriod::__wakeup()
+*/
+PHP_METHOD(DatePeriod, __wakeup)
+{
+ zval *object = getThis();
+ php_period_obj *period_obj;
+ HashTable *myht;
+
+ period_obj = zend_object_store_get_object(object TSRMLS_CC);
+
+ myht = Z_OBJPROP_P(object);
+
+ if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
+ php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
+ }
+}
+/* }}} */
+
+/* {{{ date_period_read_property */
+static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
+{
+ zval *zv;
+ if (type != BP_VAR_IS && type != BP_VAR_R) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Retrieval of DatePeriod properties for modification is unsupported");
+ }
+
+ Z_OBJPROP_P(object); /* build properties hash table */
+
+ zv = std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
+ if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) {
+ /* defensive copy */
+ zend_object_value zov = Z_OBJ_HANDLER_P(zv, clone_obj)(zv TSRMLS_CC);
+ MAKE_STD_ZVAL(zv);
+ Z_TYPE_P(zv) = IS_OBJECT;
+ Z_OBJVAL_P(zv) = zov;
+ }
+
+ return zv;
+}
+/* }}} */
+
+/* {{{ date_period_write_property */
+static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Writing to DatePeriod properties is unsupported");
+}
+/* }}} */
+
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/date/php_date.h b/ext/date/php_date.h
index 3af3fa42e..efae0a1db 100644
--- a/ext/date/php_date.h
+++ b/ext/date/php_date.h
@@ -101,6 +101,8 @@ PHP_FUNCTION(date_interval_format);
PHP_FUNCTION(date_interval_create_from_date_string);
PHP_METHOD(DatePeriod, __construct);
+PHP_METHOD(DatePeriod, __wakeup);
+PHP_METHOD(DatePeriod, __set_state);
/* Options and Configuration */
PHP_FUNCTION(date_default_timezone_set);
diff --git a/ext/date/tests/bug45682.phpt b/ext/date/tests/bug45682.phpt
index d8bbfc5a0..094c7fdf4 100644
--- a/ext/date/tests/bug45682.phpt
+++ b/ext/date/tests/bug45682.phpt
@@ -11,8 +11,8 @@ $other = new DateTime("31-July-2008");
$diff = date_diff($date, $other);
var_dump($diff);
---EXPECT--
-object(DateInterval)#3 (8) {
+--EXPECTF--
+object(DateInterval)#%d (15) {
["y"]=>
int(0)
["m"]=>
@@ -25,8 +25,22 @@ object(DateInterval)#3 (8) {
int(0)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
- int(3)
+ string(1) "3"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
diff --git a/ext/date/tests/bug48678.phpt b/ext/date/tests/bug48678.phpt
index e2cb724f7..253cb84ce 100644
--- a/ext/date/tests/bug48678.phpt
+++ b/ext/date/tests/bug48678.phpt
@@ -15,8 +15,15 @@ DateInterval Object
[h] => 12
[i] => 30
[s] => 5
+ [weekday] => 0
+ [weekday_behavior] => 0
+ [first_last_day_of] => 0
[invert] => 0
- [days] =>%s
+ [days] =>
+ [special_type] => 0
+ [special_amount] => 0
+ [have_weekday_relative] => 0
+ [have_special_relative] => 0
)
DateInterval Object
(
@@ -26,6 +33,13 @@ DateInterval Object
[h] => 12
[i] => 30
[s] => 5
+ [weekday] => 0
+ [weekday_behavior] => 0
+ [first_last_day_of] => 0
[invert] => 0
- [days] =>%s
+ [days] => 0
+ [special_type] => 0
+ [special_amount] => 0
+ [have_weekday_relative] => 0
+ [have_special_relative] => 0
)
diff --git a/ext/date/tests/bug49081.phpt b/ext/date/tests/bug49081.phpt
index f4f02903d..31f735148 100644
--- a/ext/date/tests/bug49081.phpt
+++ b/ext/date/tests/bug49081.phpt
@@ -17,6 +17,13 @@ DateInterval Object
[h] => 4
[i] => 0
[s] => 0
+ [weekday] => 0
+ [weekday_behavior] => 0
+ [first_last_day_of] => 0
[invert] => 0
[days] => 30
+ [special_type] => 0
+ [special_amount] => 0
+ [have_weekday_relative] => 0
+ [have_special_relative] => 0
)
diff --git a/ext/date/tests/bug49778.phpt b/ext/date/tests/bug49778.phpt
index 67c8e27f9..cc52a23b2 100644
--- a/ext/date/tests/bug49778.phpt
+++ b/ext/date/tests/bug49778.phpt
@@ -8,7 +8,7 @@ echo $i->format("%d"), "\n";
echo $i->format("%a"), "\n";
?>
--EXPECT--
-object(DateInterval)#1 (8) {
+object(DateInterval)#1 (15) {
["y"]=>
int(0)
["m"]=>
@@ -21,10 +21,24 @@ object(DateInterval)#1 (8) {
int(0)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
bool(false)
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
7
(unknown)
diff --git a/ext/date/tests/bug52113.phpt b/ext/date/tests/bug52113.phpt
index a7d9339d1..862e92e96 100644
--- a/ext/date/tests/bug52113.phpt
+++ b/ext/date/tests/bug52113.phpt
@@ -32,7 +32,7 @@ var_dump($unser, $p);
?>
--EXPECT--
-object(DateInterval)#3 (8) {
+object(DateInterval)#3 (15) {
["y"]=>
int(0)
["m"]=>
@@ -45,12 +45,26 @@ object(DateInterval)#3 (8) {
int(0)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
int(0)
}
-string(128) "O:12:"DateInterval":8:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:0;s:1:"h";i:4;s:1:"i";i:0;s:1:"s";i:0;s:6:"invert";i:0;s:4:"days";i:0;}"
+string(328) "O:12:"DateInterval":15:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:0;s:1:"h";i:4;s:1:"i";i:0;s:1:"s";i:0;s:7:"weekday";i:0;s:16:"weekday_behavior";i:0;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";s:1:"0";s:12:"special_type";i:0;s:14:"special_amount";s:1:"0";s:21:"have_weekday_relative";i:0;s:21:"have_special_relative";i:0;}"
DateInterval::__set_state(array(
'y' => 0,
'm' => 0,
@@ -58,9 +72,16 @@ DateInterval::__set_state(array(
'h' => 4,
'i' => 0,
's' => 0,
+ 'weekday' => 0,
+ 'weekday_behavior' => 0,
+ 'first_last_day_of' => 0,
'invert' => 0,
- 'days' => 0,
-))object(DateInterval)#5 (8) {
+ 'days' => '0',
+ 'special_type' => 0,
+ 'special_amount' => '0',
+ 'have_weekday_relative' => 0,
+ 'have_special_relative' => 0,
+))object(DateInterval)#5 (15) {
["y"]=>
int(0)
["m"]=>
@@ -73,14 +94,78 @@ DateInterval::__set_state(array(
int(0)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
int(0)
}
-object(DatePeriod)#6 (0) {
+object(DatePeriod)#6 (6) {
+ ["start"]=>
+ object(DateTime)#4 (3) {
+ ["date"]=>
+ string(19) "2003-01-02 08:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["current"]=>
+ NULL
+ ["end"]=>
+ NULL
+ ["interval"]=>
+ object(DateInterval)#7 (15) {
+ ["y"]=>
+ int(0)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(0)
+ ["h"]=>
+ int(4)
+ ["i"]=>
+ int(0)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+ }
+ ["recurrences"]=>
+ int(3)
+ ["include_start_date"]=>
+ bool(true)
}
-object(DateInterval)#4 (8) {
+object(DateInterval)#8 (15) {
["y"]=>
int(7)
["m"]=>
@@ -93,10 +178,74 @@ object(DateInterval)#4 (8) {
int(3)
["s"]=>
int(2)
+ ["weekday"]=>
+ int(-1)
+ ["weekday_behavior"]=>
+ int(-1)
+ ["first_last_day_of"]=>
+ int(-1)
["invert"]=>
int(1)
["days"]=>
- int(2400)
+ string(4) "2400"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(2) "-1"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
-object(DatePeriod)#7 (0) {
+object(DatePeriod)#9 (6) {
+ ["start"]=>
+ object(DateTime)#6 (3) {
+ ["date"]=>
+ string(19) "2003-01-02 08:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["current"]=>
+ NULL
+ ["end"]=>
+ NULL
+ ["interval"]=>
+ object(DateInterval)#7 (15) {
+ ["y"]=>
+ int(0)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(0)
+ ["h"]=>
+ int(4)
+ ["i"]=>
+ int(0)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+ }
+ ["recurrences"]=>
+ int(3)
+ ["include_start_date"]=>
+ bool(true)
}
diff --git a/ext/date/tests/bug52738.phpt b/ext/date/tests/bug52738.phpt
index fc1b6029e..ea219f7c7 100644
--- a/ext/date/tests/bug52738.phpt
+++ b/ext/date/tests/bug52738.phpt
@@ -27,6 +27,13 @@ di Object
[h] => 0
[i] => 0
[s] => 0
+ [weekday] => 0
+ [weekday_behavior] => 0
+ [first_last_day_of] => 0
[invert] => 0
[days] =>
+ [special_type] => 0
+ [special_amount] => 0
+ [have_weekday_relative] => 0
+ [have_special_relative] => 0
)
diff --git a/ext/date/tests/bug52808.phpt b/ext/date/tests/bug52808.phpt
index e031ac6ee..e3b38bb5f 100644
--- a/ext/date/tests/bug52808.phpt
+++ b/ext/date/tests/bug52808.phpt
@@ -25,7 +25,7 @@ foreach($intervals as $iv) {
echo "==DONE==\n";
?>
--EXPECTF--
-object(DateInterval)#%d (8) {
+object(DateInterval)#%d (15) {
["y"]=>
int(1)
["m"]=>
@@ -38,12 +38,26 @@ object(DateInterval)#%d (8) {
int(30)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(1)
["days"]=>
- int(437)
+ string(3) "437"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
-object(DateInterval)#%d (8) {
+object(DateInterval)#%d (15) {
["y"]=>
int(0)
["m"]=>
@@ -56,12 +70,26 @@ object(DateInterval)#%d (8) {
int(30)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
- int(294)
+ string(3) "294"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
-object(DateInterval)#%d (8) {
+object(DateInterval)#%d (15) {
["y"]=>
int(0)
["m"]=>
@@ -74,10 +102,24 @@ object(DateInterval)#%d (8) {
int(30)
["s"]=>
int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
- int(294)
+ string(3) "294"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
DateInterval::__construct(): Failed to parse interval (2007-05-11T15:30:00Z/)
DateInterval::__construct(): Failed to parse interval (2007-05-11T15:30:00Z)
diff --git a/ext/date/tests/bug53437.phpt b/ext/date/tests/bug53437.phpt
index f08986653..7a282ab6c 100644
--- a/ext/date/tests/bug53437.phpt
+++ b/ext/date/tests/bug53437.phpt
@@ -1,7 +1,5 @@
--TEST--
-Bug #53437 (Crash when using unserialized DatePeriod instance)
---XFAIL--
-Bug #53437 Not fixed yet
+Bug #53437 (Crash when using unserialized DatePeriod instance), variation 1
--FILE--
<?php
$dp = new DatePeriod(new DateTime('2010-01-01 UTC'), new DateInterval('P1D'), 2);
@@ -20,9 +18,137 @@ $dpu = unserialize($ser); // $dpu has invalid values???
var_dump($dpu);
echo "Unserialized:\r\n";
-// ???which leads to CRASH:
foreach($dpu as $dt) {
echo $dt->format('Y-m-d H:i:s')."\r\n";
}
?>
+==DONE==
--EXPECT--
+Original:
+2010-01-01 00:00:00
+2010-01-02 00:00:00
+2010-01-03 00:00:00
+
+object(DatePeriod)#1 (6) {
+ ["start"]=>
+ object(DateTime)#2 (3) {
+ ["date"]=>
+ string(19) "2010-01-01 00:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["current"]=>
+ object(DateTime)#4 (3) {
+ ["date"]=>
+ string(19) "2010-01-04 00:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["end"]=>
+ NULL
+ ["interval"]=>
+ object(DateInterval)#5 (15) {
+ ["y"]=>
+ int(0)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(1)
+ ["h"]=>
+ int(0)
+ ["i"]=>
+ int(0)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ bool(false)
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+ }
+ ["recurrences"]=>
+ int(3)
+ ["include_start_date"]=>
+ bool(true)
+}
+object(DatePeriod)#5 (6) {
+ ["start"]=>
+ object(DateTime)#10 (3) {
+ ["date"]=>
+ string(19) "2010-01-01 00:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["current"]=>
+ object(DateTime)#7 (3) {
+ ["date"]=>
+ string(19) "2010-01-04 00:00:00"
+ ["timezone_type"]=>
+ int(3)
+ ["timezone"]=>
+ string(3) "UTC"
+ }
+ ["end"]=>
+ NULL
+ ["interval"]=>
+ object(DateInterval)#8 (15) {
+ ["y"]=>
+ int(0)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(1)
+ ["h"]=>
+ int(0)
+ ["i"]=>
+ int(0)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+ }
+ ["recurrences"]=>
+ int(3)
+ ["include_start_date"]=>
+ bool(true)
+}
+Unserialized:
+2010-01-01 00:00:00
+2010-01-02 00:00:00
+2010-01-03 00:00:00
+==DONE==
diff --git a/ext/date/tests/bug53437_var1.phpt b/ext/date/tests/bug53437_var1.phpt
new file mode 100644
index 000000000..f1f9843d5
--- /dev/null
+++ b/ext/date/tests/bug53437_var1.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Bug #53437 (Crash when using unserialized DatePeriod instance), variation 2
+--FILE--
+<?php
+$s = 'O:10:"DatePeriod":0:{}';
+
+$dp = unserialize($s);
+
+var_dump($dp);
+?>
+==DONE==
+--EXPECTF--
+Fatal error: Invalid serialization data for DatePeriod object in %sbug53437_var1.php on line %d
diff --git a/ext/date/tests/bug53437_var2.phpt b/ext/date/tests/bug53437_var2.phpt
new file mode 100644
index 000000000..70565960e
--- /dev/null
+++ b/ext/date/tests/bug53437_var2.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Bug #53437 DateInterval basic serialization
+--FILE--
+<?php
+$di0 = new DateInterval('P2Y4DT6H8M');
+
+$s = serialize($di0);
+
+$di1 = unserialize($s);
+
+var_dump($di0, $di1);
+
+?>
+==DONE==
+--EXPECT--
+object(DateInterval)#1 (15) {
+ ["y"]=>
+ int(2)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(4)
+ ["h"]=>
+ int(6)
+ ["i"]=>
+ int(8)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ bool(false)
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+}
+object(DateInterval)#2 (15) {
+ ["y"]=>
+ int(2)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(4)
+ ["h"]=>
+ int(6)
+ ["i"]=>
+ int(8)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
+}
+==DONE==
diff --git a/ext/date/tests/bug53437_var3.phpt b/ext/date/tests/bug53437_var3.phpt
new file mode 100644
index 000000000..06f68df61
--- /dev/null
+++ b/ext/date/tests/bug53437_var3.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Bug #53437 DateInterval unserialize bad data
+--FILE--
+<?php
+$s = 'O:12:"DateInterval":15:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:7:"weekday";i:10;s:16:"weekday_behavior";i:10;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";s:4:"aoeu";s:12:"special_type";i:0;s:14:"special_amount";s:21:"234523452345234532455";s:21:"have_weekday_relative";i:21474836489;s:21:"have_special_relative";s:3:"bla";}';
+
+$di = unserialize($s);
+var_dump($di);
+
+?>
+==DONE==
+--EXPECT--
+object(DateInterval)#1 (15) {
+ ["y"]=>
+ int(2)
+ ["m"]=>
+ int(0)
+ ["d"]=>
+ int(0)
+ ["h"]=>
+ int(6)
+ ["i"]=>
+ int(8)
+ ["s"]=>
+ int(0)
+ ["weekday"]=>
+ int(10)
+ ["weekday_behavior"]=>
+ int(10)
+ ["first_last_day_of"]=>
+ int(0)
+ ["invert"]=>
+ int(0)
+ ["days"]=>
+ string(1) "0"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(19) "9223372036854775807"
+ ["have_weekday_relative"]=>
+ int(9)
+ ["have_special_relative"]=>
+ int(0)
+}
+==DONE==
diff --git a/ext/date/tests/bug55397.phpt b/ext/date/tests/bug55397.phpt
index efc09b504..13778a00b 100644
--- a/ext/date/tests/bug55397.phpt
+++ b/ext/date/tests/bug55397.phpt
@@ -7,5 +7,4 @@ date_default_timezone_set('Europe/Prague');
var_dump(unserialize('O:8:"DateTime":0:{}') == new DateTime);
?>
--EXPECTF--
-Warning: %s: Trying to compare an incomplete DateTime object in %s on line %d
-bool(false)
+Fatal error: Invalid serialization data for DateTime object in %sbug55397.php on line %d
diff --git a/ext/date/tests/bug62852.phpt b/ext/date/tests/bug62852.phpt
index 26de51021..7013a3f97 100644
--- a/ext/date/tests/bug62852.phpt
+++ b/ext/date/tests/bug62852.phpt
@@ -1,36 +1,14 @@
--TEST--
-Bug #62852 (Unserialize invalid DateTime causes crash)
+Bug #62852 (Unserialize invalid DateTime causes crash), variation 1
--INI--
date.timezone=GMT
---XFAIL--
-bug is not fixed yet
--FILE--
<?php
$s1 = 'O:8:"DateTime":3:{s:4:"date";s:20:"10007-06-07 03:51:49";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}';
-$s2 = 'O:3:"Foo":3:{s:4:"date";s:20:"10007-06-07 03:51:49";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}';
-global $foo;
-
-class Foo extends DateTime {
- function __wakeup() {
- global $foo;
- $foo = $this;
- parent::__wakeup();
- }
-}
-
-// Old test case
try {
unserialize( $s1 );
} catch ( Exception $e ) {}
-// My test case
-try {
- unserialize( $s2 );
-} catch ( Exception $e ) {}
-var_dump( $foo );
-
-echo "okey";
-?>
--EXPECTF--
-okey
+Fatal error: Invalid serialization data for DateTime object in %sbug62852.php on line %d
diff --git a/ext/date/tests/bug62852_var2.phpt b/ext/date/tests/bug62852_var2.phpt
new file mode 100644
index 000000000..f93ba28ab
--- /dev/null
+++ b/ext/date/tests/bug62852_var2.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #62852 (Unserialize invalid DateTime causes crash), variation 2
+--INI--
+date.timezone=GMT
+--FILE--
+<?php
+$s2 = 'O:3:"Foo":3:{s:4:"date";s:20:"10007-06-07 03:51:49";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}';
+
+global $foo;
+
+class Foo extends DateTime {
+ function __wakeup() {
+ global $foo;
+ $foo = $this;
+ parent::__wakeup();
+ }
+}
+
+try {
+ unserialize( $s2 );
+} catch ( Exception $e ) {}
+var_dump( $foo );
+
+--EXPECTF--
+Fatal error: Invalid serialization data for DateTime object in %sbug62852_var2.php on line %d
diff --git a/ext/date/tests/bug62852_var3.phpt b/ext/date/tests/bug62852_var3.phpt
new file mode 100644
index 000000000..5a644b547
--- /dev/null
+++ b/ext/date/tests/bug62852_var3.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #62852 (Unserialize invalid DateTime causes crash), variation 3
+--INI--
+date.timezone=GMT
+--FILE--
+<?php
+$s2 = 'O:3:"Foo":3:{s:4:"date";s:19:"0000-00-00 00:00:00";s:13:"timezone_type";i:0;s:8:"timezone";s:3:"UTC";}';
+
+global $foo;
+
+class Foo extends DateTime {
+ function __wakeup() {
+ global $foo;
+ $foo = $this;
+ parent::__wakeup();
+ }
+}
+
+try {
+ unserialize( $s2 );
+} catch ( Exception $e ) {}
+var_dump( $foo );
+
+--EXPECTF--
+Fatal error: Invalid serialization data for DateTime object in %sbug62852_var3.php on line %d
diff --git a/ext/date/tests/date_diff1.phpt b/ext/date/tests/date_diff1.phpt
index cf32fcbf3..3f3d1da7a 100644
--- a/ext/date/tests/date_diff1.phpt
+++ b/ext/date/tests/date_diff1.phpt
@@ -28,7 +28,7 @@ object(DateTime)#2 (3) {
["timezone"]=>
string(3) "EDT"
}
-object(DateInterval)#3 (8) {
+object(DateInterval)#3 (15) {
["y"]=>
int(0)
["m"]=>
@@ -41,8 +41,22 @@ object(DateInterval)#3 (8) {
int(19)
["s"]=>
int(40)
+ ["weekday"]=>
+ int(0)
+ ["weekday_behavior"]=>
+ int(0)
+ ["first_last_day_of"]=>
+ int(0)
["invert"]=>
int(0)
["days"]=>
- int(33)
+ string(2) "33"
+ ["special_type"]=>
+ int(0)
+ ["special_amount"]=>
+ string(1) "0"
+ ["have_weekday_relative"]=>
+ int(0)
+ ["have_special_relative"]=>
+ int(0)
}
diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c
index f4183d2f9..6c8cf84e9 100644
--- a/ext/dom/dom_iterators.c
+++ b/ext/dom/dom_iterators.c
@@ -157,35 +157,22 @@ static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***da
}
/* }}} */
-static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
- zval *curobj;
- xmlNodePtr curnode = NULL;
- dom_object *intern;
- zval *object;
- int namelen;
-
php_dom_iterator *iterator = (php_dom_iterator *)iter;
-
- object = (zval *)iterator->intern.data;
+ zval *object = (zval *)iterator->intern.data;
if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) {
- *int_key = iter->index;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iter->index);
} else {
- curobj = iterator->curobj;
+ dom_object *intern = (dom_object *)zend_object_store_get_object(iterator->curobj TSRMLS_CC);
- intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
if (intern != NULL && intern->ptr != NULL) {
- curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
+ xmlNodePtr curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
+ ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1);
} else {
- return HASH_KEY_NON_EXISTANT;
+ ZVAL_NULL(key);
}
-
- namelen = xmlStrlen(curnode->name);
- *str_key = estrndup(curnode->name, namelen);
- *str_key_len = namelen + 1;
- return HASH_KEY_IS_STRING;
}
}
/* }}} */
diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp
index d88ad8a71..3748991ae 100644
--- a/ext/intl/breakiterator/breakiterator_iterators.cpp
+++ b/ext/intl/breakiterator/breakiterator_iterators.cpp
@@ -139,14 +139,10 @@ static void _breakiterator_parts_destroy_it(zend_object_iterator *iter TSRMLS_DC
zval_ptr_dtor(reinterpret_cast<zval**>(&iter->data));
}
-static int _breakiterator_parts_get_current_key(zend_object_iterator *iter,
- char **str_key,
- uint *str_key_len,
- ulong *int_key TSRMLS_DC)
+static void _breakiterator_parts_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
/* the actual work is done in move_forward and rewind */
- *int_key = iter->index;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iter->index);
}
static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_DC)
@@ -343,4 +339,4 @@ U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D)
PARTSITER_DECL_LONG_CONST(KEY_RIGHT);
#undef PARTSITER_DECL_LONG_CONST
-} \ No newline at end of file
+}
diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp
index da47a437a..3ba785582 100644
--- a/ext/intl/common/common_enum.cpp
+++ b/ext/intl/common/common_enum.cpp
@@ -251,19 +251,7 @@ static PHP_METHOD(IntlIterator, key)
INTLITERATOR_METHOD_FETCH_OBJECT;
if (ii->iterator->funcs->get_current_key) {
- char *str_key;
- uint str_key_len;
- ulong int_key;
-
- switch (ii->iterator->funcs->get_current_key(
- ii->iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
- case HASH_KEY_IS_LONG:
- RETURN_LONG(int_key);
- break;
- case HASH_KEY_IS_STRING:
- RETURN_STRINGL(str_key, str_key_len-1, 0);
- break;
- }
+ ii->iterator->funcs->get_current_key(ii->iterator, return_value TSRMLS_CC);
} else {
RETURN_LONG(ii->iterator->index);
}
diff --git a/ext/intl/resourcebundle/resourcebundle_iterator.c b/ext/intl/resourcebundle/resourcebundle_iterator.c
index 16e1b9287..78236fda5 100644
--- a/ext/intl/resourcebundle/resourcebundle_iterator.c
+++ b/ext/intl/resourcebundle/resourcebundle_iterator.c
@@ -101,21 +101,18 @@ static void resourcebundle_iterator_current( zend_object_iterator *iter, zval **
/* }}} */
/* {{{ resourcebundle_iterator_key */
-static int resourcebundle_iterator_key( zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC )
+static void resourcebundle_iterator_key( zend_object_iterator *iter, zval *key TSRMLS_DC )
{
ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
if (!iterator->current) {
resourcebundle_iterator_read( iterator TSRMLS_CC);
}
+
if (iterator->is_table) {
- *str_key = estrdup( iterator->currentkey );
- *str_key_len = strlen( iterator->currentkey ) + 1;
- return HASH_KEY_IS_STRING;
- }
- else {
- *int_key = iterator->i;
- return HASH_KEY_IS_LONG;
+ ZVAL_STRING(key, iterator->currentkey, 1);
+ } else {
+ ZVAL_LONG(key, iterator->i);
}
}
/* }}} */
diff --git a/ext/mysqli/mysqli_result_iterator.c b/ext/mysqli/mysqli_result_iterator.c
index 0f5ccdd63..3ea7bafe4 100644
--- a/ext/mysqli/mysqli_result_iterator.c
+++ b/ext/mysqli/mysqli_result_iterator.c
@@ -150,12 +150,11 @@ static void php_mysqli_result_iterator_rewind(zend_object_iterator *iter TSRMLS_
/* {{{ php_mysqli_result_iterator_current_key */
-static int php_mysqli_result_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+static void php_mysqli_result_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
php_mysqli_result_iterator *iterator = (php_mysqli_result_iterator*) iter;
- *int_key = (ulong) iterator->row_num;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iterator->row_num);
}
/* }}} */
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 4916c0650..15b293825 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -1463,7 +1463,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigne
if (stmt->param_count) {
if (!stmt->param_bind) {
- stmt->param_bind = mnd_ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND));
+ stmt->param_bind = mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent);
if (!stmt->param_bind) {
DBG_RETURN(FAIL);
}
diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h
index d8d7d0f47..155e57d2c 100644
--- a/ext/oci8/php_oci8_int.h
+++ b/ext/oci8/php_oci8_int.h
@@ -191,7 +191,7 @@ typedef struct { /* php_oci_statement {{{ */
sword errcode; /* last errcode*/
OCIError *err; /* private error handle */
OCIStmt *stmt; /* statement handle */
- char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */
+ char *last_query; /* last query issued. also used to determine if this is a statement or a refcursor received from Oracle */
long last_query_len; /* last query length */
HashTable *columns; /* hash containing all the result columns */
HashTable *binds; /* binds hash */
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
new file mode 100644
index 000000000..d4299c8ad
--- /dev/null
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -0,0 +1,2028 @@
+#define DEBUG_BLOCKPASS 0
+
+/* Checks if a constant (like "true") may be replaced by its value */
+static int zend_get_persistent_constant(char *name, uint name_len, zval *result, int copy TSRMLS_DC ELS_DC)
+{
+ zend_constant *c;
+ char *lookup_name;
+ int retval = 1;
+ ALLOCA_FLAG(use_heap);
+
+ if (zend_hash_find(EG(zend_constants), name, name_len + 1, (void **) &c) == FAILURE) {
+ lookup_name = DO_ALLOCA(name_len + 1);
+ memcpy(lookup_name, name, name_len + 1);
+ zend_str_tolower(lookup_name, name_len);
+
+ if (zend_hash_find(EG(zend_constants), lookup_name, name_len + 1, (void **) &c) == SUCCESS) {
+ if (!(c->flags & CONST_CT_SUBST) || (c->flags & CONST_CS)) {
+ retval = 0;
+ }
+ } else {
+ retval = 0;
+ }
+ FREE_ALLOCA(lookup_name);
+ }
+
+ if (retval) {
+ if (c->flags & CONST_PERSISTENT) {
+ *result = c->value;
+ if (copy) {
+ zval_copy_ctor(result);
+ }
+ } else {
+ retval = 0;
+ }
+ }
+
+ return retval;
+}
+
+#if DEBUG_BLOCKPASS
+# define BLOCK_REF(b) b?op_array->opcodes-b->start_opline:-1
+
+static inline void print_block(zend_code_block *block, zend_op *opcodes, char *txt)
+{
+ fprintf(stderr, "%sBlock: %d-%d (%d)", txt, block->start_opline - opcodes, block->start_opline - opcodes + block->len - 1, block->len);
+ if (!block->access) {
+ fprintf(stderr, " unused");
+ }
+ if (block->op1_to) {
+ fprintf(stderr, " 1: %d", block->op1_to->start_opline - opcodes);
+ }
+ if (block->op2_to) {
+ fprintf(stderr, " 2: %d", block->op2_to->start_opline - opcodes);
+ }
+ if (block->ext_to) {
+ fprintf(stderr, " e: %d", block->ext_to->start_opline - opcodes);
+ }
+ if (block->follow_to) {
+ fprintf(stderr, " f: %d", block->follow_to->start_opline - opcodes);
+ }
+
+ if (block->sources) {
+ zend_block_source *bs = block->sources;
+ fprintf(stderr, " s:");
+ while (bs) {
+ fprintf(stderr, " %d", bs->from->start_opline - opcodes);
+ bs = bs->next;
+ }
+ }
+
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+#else
+#define print_block(a,b,c)
+#endif
+
+#define START_BLOCK_OP(opno) blocks[opno].start_opline = &op_array->opcodes[opno]; blocks[opno].start_opline_no = opno; blocks[opno].access = 1
+
+/* find code blocks in op_array
+ code block is a set of opcodes with single flow of control, i.e. without jmps,
+ branches, etc. */
+static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg)
+{
+ zend_op *opline;
+ zend_op *end = op_array->opcodes + op_array->last;
+ zend_code_block *blocks, *cur_block;
+ zend_uint opno = 0;
+
+ memset(cfg, 0, sizeof(zend_cfg));
+ blocks = cfg->blocks = ecalloc(op_array->last + 2, sizeof(zend_code_block));
+ opline = op_array->opcodes;
+ blocks[0].start_opline = opline;
+ blocks[0].start_opline_no = 0;
+ while (opline < end) {
+ switch((unsigned)opline->opcode) {
+ case ZEND_BRK:
+ case ZEND_CONT:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_GOTO:
+#endif
+ /* would not optimize non-optimized BRK/CONTs - we cannot
+ really know where it jumps, so these optimizations are
+ too dangerous */
+ efree(blocks);
+ return 0;
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+ START_BLOCK_OP(ZEND_OP1(opline).opline_num);
+ break;
+#endif
+ case ZEND_JMP:
+ START_BLOCK_OP(ZEND_OP1(opline).opline_num);
+ /* break missing intentionally */
+ case ZEND_RETURN:
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_RETURN_BY_REF:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_RET:
+#endif
+ case ZEND_EXIT:
+ case ZEND_THROW:
+ /* start new block from this+1 */
+ START_BLOCK_OP(opno + 1);
+ break;
+ /* TODO: if conditional jmp depends on constant,
+ don't start block that won't be executed */
+ case ZEND_CATCH:
+ START_BLOCK_OP(opline->extended_value);
+ START_BLOCK_OP(opno + 1);
+ break;
+ case ZEND_JMPZNZ:
+ START_BLOCK_OP(opline->extended_value);
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_FE_FETCH:
+ case ZEND_FE_RESET:
+ case ZEND_NEW:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ START_BLOCK_OP(ZEND_OP2(opline).opline_num);
+ START_BLOCK_OP(opno + 1);
+ break;
+
+ }
+ opno++;
+ opline++;
+ }
+
+ /* first find block start points */
+ if (op_array->last_try_catch) {
+ int i;
+ cfg->try = ecalloc(op_array->last_try_catch, sizeof(zend_code_block *));
+ cfg->catch = ecalloc(op_array->last_try_catch, sizeof(zend_code_block *));
+ for (i = 0; i< op_array->last_try_catch; i++) {
+ cfg->try[i] = &blocks[op_array->try_catch_array[i].try_op];
+ cfg->catch[i] = &blocks[op_array->try_catch_array[i].catch_op];
+ START_BLOCK_OP(op_array->try_catch_array[i].try_op);
+ START_BLOCK_OP(op_array->try_catch_array[i].catch_op);
+ blocks[op_array->try_catch_array[i].try_op].protected = 1;
+ }
+ }
+ /* Currently, we don't optimize op_arrays with BRK/CONT/GOTO opcodes,
+ * but, we have to keep brk_cont_array to avoid memory leaks during
+ * exception handling */
+ if (op_array->last_brk_cont) {
+ int i, j;
+
+ j = 0;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ if (op_array->brk_cont_array[i].start >= 0 &&
+ (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_SWITCH_FREE)) {
+ int parent = op_array->brk_cont_array[i].parent;
+
+ while (parent >= 0 &&
+ op_array->brk_cont_array[parent].start < 0 &&
+ op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE &&
+ op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_SWITCH_FREE) {
+ parent = op_array->brk_cont_array[parent].parent;
+ }
+ op_array->brk_cont_array[i].parent = parent;
+ j++;
+ }
+ }
+ if (j) {
+ cfg->loop_start = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *));
+ cfg->loop_cont = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *));
+ cfg->loop_brk = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *));
+ j = 0;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ if (op_array->brk_cont_array[i].start >= 0 &&
+ (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_SWITCH_FREE)) {
+ if (i != j) {
+ op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
+ }
+ cfg->loop_start[j] = &blocks[op_array->brk_cont_array[j].start];
+ cfg->loop_cont[j] = &blocks[op_array->brk_cont_array[j].cont];
+ cfg->loop_brk[j] = &blocks[op_array->brk_cont_array[j].brk];
+ START_BLOCK_OP(op_array->brk_cont_array[j].start);
+ START_BLOCK_OP(op_array->brk_cont_array[j].cont);
+ START_BLOCK_OP(op_array->brk_cont_array[j].brk);
+ blocks[op_array->brk_cont_array[j].start].protected = 1;
+ blocks[op_array->brk_cont_array[j].brk].protected = 1;
+ j++;
+ }
+ }
+ op_array->last_brk_cont = j;
+ } else {
+ efree(op_array->brk_cont_array);
+ op_array->brk_cont_array = NULL;
+ op_array->last_brk_cont = 0;
+ }
+ }
+
+ /* Build CFG (Control Flow Graph) */
+ cur_block = blocks;
+ for (opno = 1; opno < op_array->last; opno++) {
+ if (blocks[opno].start_opline) {
+ /* found new block start */
+ cur_block->len = blocks[opno].start_opline - cur_block->start_opline;
+ cur_block->next = &blocks[opno];
+ /* what is the last OP of previous block? */
+ opline = blocks[opno].start_opline - 1;
+ switch((unsigned)opline->opcode) {
+ case ZEND_RETURN:
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_RETURN_BY_REF:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_RET:
+#endif
+ case ZEND_EXIT:
+ case ZEND_THROW:
+ break;
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+#endif
+ case ZEND_JMP:
+ cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
+ break;
+ case ZEND_JMPZNZ:
+ cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
+ cur_block->ext_to = &blocks[opline->extended_value];
+ break;
+ case ZEND_CATCH:
+ cur_block->ext_to = &blocks[opline->extended_value];
+ cur_block->follow_to = &blocks[opno];
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_FE_RESET:
+ case ZEND_NEW:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ case ZEND_FE_FETCH:
+ cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
+ /* break missing intentionally */
+ default:
+ /* next block follows this */
+ cur_block->follow_to = &blocks[opno];
+ break;
+ }
+ print_block(cur_block, op_array->opcodes, "");
+ cur_block = cur_block->next;
+ }
+ }
+ cur_block->len = end - cur_block->start_opline;
+ cur_block->next = &blocks[op_array->last + 1];
+ print_block(cur_block, op_array->opcodes, "");
+
+ return 1;
+}
+
+/* CFG back references management */
+
+#define ADD_SOURCE(fromb, tob) { \
+ zend_block_source *__s = tob->sources; \
+ while (__s && __s->from != fromb) __s = __s->next; \
+ if (__s == NULL) { \
+ zend_block_source *__t = emalloc(sizeof(zend_block_source)); \
+ __t->next = tob->sources; \
+ tob->sources = __t; \
+ __t->from = fromb; \
+ } \
+}
+
+#define DEL_SOURCE(cs) { \
+ zend_block_source *__ns = (*cs)->next; \
+ efree(*cs); \
+ *cs = __ns; \
+}
+
+
+static inline void replace_source(zend_block_source *list, zend_code_block *old, zend_code_block *new)
+{
+ /* replace all references to 'old' in 'list' with 'new' */
+ zend_block_source **cs;
+ int found = 0;
+
+ for (cs = &list; *cs; cs = &((*cs)->next)) {
+ if ((*cs)->from == new) {
+ if (found) {
+ DEL_SOURCE(cs);
+ } else {
+ found = 1;
+ }
+ }
+
+ if ((*cs)->from == old) {
+ if (found) {
+ DEL_SOURCE(cs);
+ } else {
+ (*cs)->from = new;
+ found = 1;
+ }
+ }
+ }
+}
+
+static inline void del_source(zend_code_block *from, zend_code_block *to)
+{
+ /* delete source 'from' from 'to'-s sources list */
+ zend_block_source **cs = &to->sources;
+
+ if (to->sources == NULL) {
+ to->access = 0;
+ return;
+ }
+
+ while (*cs) {
+ if ((*cs)->from == from) {
+ DEL_SOURCE(cs);
+ break;
+ }
+ cs = &((*cs)->next);
+ }
+
+ if (to->sources == NULL) {
+ /* 'to' has no more sources - it's unused, will be stripped */
+ to->access = 0;
+ return;
+ }
+
+ if (to->sources->next == NULL) {
+ /* source to only one block */
+ zend_code_block *from_block = to->sources->from;
+
+ if (from_block->access && from_block->follow_to == to &&
+ from_block->op1_to == NULL &&
+ from_block->op2_to == NULL &&
+ from_block->ext_to == NULL) {
+ /* this block follows it's only predecessor - we can join them */
+ zend_op *new_to = from_block->start_opline + from_block->len;
+ if (new_to != to->start_opline) {
+ /* move block to new location */
+ memmove(new_to, to->start_opline, sizeof(zend_op)*to->len);
+ }
+ /* join blocks' lengths */
+ from_block->len += to->len;
+ /* move 'to'`s references to 'from' */
+ to->start_opline = NULL;
+ to->access = 0;
+ efree(to->sources);
+ to->sources = NULL;
+ from_block->follow_to = to->follow_to;
+ if (to->op1_to) {
+ from_block->op1_to = to->op1_to;
+ replace_source(to->op1_to->sources, to, from_block);
+ }
+ if (to->op2_to) {
+ from_block->op2_to = to->op2_to;
+ replace_source(to->op2_to->sources, to, from_block);
+ }
+ if (to->ext_to) {
+ from_block->ext_to = to->ext_to;
+ replace_source(to->ext_to->sources, to, from_block);
+ }
+ if (to->follow_to) {
+ replace_source(to->follow_to->sources, to, from_block);
+ }
+ /* remove "to" from list */
+ }
+ }
+}
+
+static void delete_code_block(zend_code_block *block)
+{
+ if (block->protected) {
+ return;
+ }
+ if (block->follow_to) {
+ zend_block_source *bs = block->sources;
+ while (bs) {
+ zend_code_block *from_block = bs->from;
+ zend_code_block *to = block->follow_to;
+ if (from_block->op1_to == block) {
+ from_block->op1_to = to;
+ ADD_SOURCE(from_block, to);
+ }
+ if (from_block->op2_to == block) {
+ from_block->op2_to = to;
+ ADD_SOURCE(from_block, to);
+ }
+ if (from_block->ext_to == block) {
+ from_block->ext_to = to;
+ ADD_SOURCE(from_block, to);
+ }
+ if (from_block->follow_to == block) {
+ from_block->follow_to = to;
+ ADD_SOURCE(from_block, to);
+ }
+ bs = bs->next;
+ }
+ }
+ block->access = 0;
+}
+
+static void zend_access_path(zend_code_block *block)
+{
+ if (block->access) {
+ return;
+ }
+
+ block->access = 1;
+ if (block->op1_to) {
+ zend_access_path(block->op1_to);
+ ADD_SOURCE(block, block->op1_to);
+ }
+ if (block->op2_to) {
+ zend_access_path(block->op2_to);
+ ADD_SOURCE(block, block->op2_to);
+ }
+ if (block->ext_to) {
+ zend_access_path(block->ext_to);
+ ADD_SOURCE(block, block->ext_to);
+ }
+ if (block->follow_to) {
+ zend_access_path(block->follow_to);
+ ADD_SOURCE(block, block->follow_to);
+ }
+}
+
+/* Traverse CFG, mark reachable basic blocks and build back references */
+static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int find_start)
+{
+ zend_code_block *blocks = cfg->blocks;
+ zend_code_block *start = find_start? NULL : blocks;
+ zend_code_block *b;
+
+ /* Mark all blocks as unaccessible and destroy back references */
+ b = blocks;
+ while (b != NULL) {
+ zend_block_source *cs;
+ if (!start && b->access) {
+ start = b;
+ }
+ b->access = 0;
+ cs = b->sources;
+ while (cs) {
+ zend_block_source *n = cs->next;
+ efree(cs);
+ cs = n;
+ }
+ b->sources = NULL;
+ b = b->next;
+ }
+
+ /* Walk thorough all paths */
+ zend_access_path(start);
+
+ /* Add brk/cont paths */
+ if (op_array->last_brk_cont) {
+ int i;
+ for (i=0; i< op_array->last_brk_cont; i++) {
+ zend_access_path(cfg->loop_start[i]);
+ zend_access_path(cfg->loop_cont[i]);
+ zend_access_path(cfg->loop_brk[i]);
+ }
+ }
+
+ /* Add exception paths */
+ if (op_array->last_try_catch) {
+ int i;
+ for (i=0; i< op_array->last_try_catch; i++) {
+ if (!cfg->catch[i]->access) {
+ zend_access_path(cfg->catch[i]);
+ }
+ }
+ }
+}
+
+/* Data dependencies macros */
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+
+# define VAR_NUM_EX(op) ((op ## _type & (IS_TMP_VAR|IS_VAR))?VAR_NUM((op).var):(op).var)
+
+# define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
+# define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
+
+# define VAR_UNSET(op) do { if (op ## _type & (IS_TMP_VAR|IS_VAR)) {VAR_SOURCE(op) = NULL;}} while (0)
+
+#else
+
+# define VAR_NUM_EX(op) ((op).op_type == IS_TMP_VAR || (op).op_type == IS_VAR? VAR_NUM((op).u.var) : (op).u.var)
+
+# define VAR_SOURCE(op) Tsource[VAR_NUM(op.u.var)]
+# define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(ZEND_RESULT(opline).var)] = opline
+
+# define VAR_UNSET(op) do { if ((op).op_type == IS_TMP_VAR || (op).op_type == IS_VAR) {VAR_SOURCE(op) = NULL;}} while (0)
+
+#endif
+
+#define convert_to_string_safe(v) \
+ if (Z_TYPE_P((v)) == IS_NULL) { \
+ ZVAL_STRINGL((v), "", 0, 1); \
+ } else { \
+ convert_to_string((v)); \
+ }
+
+static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, char *used_ext TSRMLS_DC)
+{
+ zend_op *opline = block->start_opline;
+ zend_op *end, *last_op = NULL;
+ zend_op **Tsource = NULL;
+
+ print_block(block, op_array->opcodes, "Opt ");
+
+ /* remove leading NOPs */
+ while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
+ if (block->len == 1) {
+ /* this block is all NOPs, join with following block */
+ if (block->follow_to) {
+ delete_code_block(block);
+ }
+ return;
+ }
+ block->start_opline++;
+ block->start_opline_no++;
+ block->len--;
+ }
+
+ /* we track data dependencies only insight a single basic block */
+ if (op_array->T) {
+ Tsource = ecalloc(op_array->T, sizeof(zend_op *));
+ }
+ opline = block->start_opline;
+ end = opline + block->len;
+ while ((op_array->T) && (opline < end)) {
+ /* strip X = QM_ASSIGN(const) */
+ if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN &&
+ ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
+ opline->opcode != ZEND_CASE && /* CASE _always_ expects variable */
+ opline->opcode != ZEND_FETCH_DIM_TMP_VAR && /* in 5.1, FETCH_DIM_TMP_VAR expects T */
+ opline->opcode != ZEND_FE_RESET &&
+ opline->opcode != ZEND_FREE
+ ) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ }
+
+ /* T = QM_ASSIGN(C), F(T) => NOP, F(C) */
+ if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op2) &&
+ VAR_SOURCE(opline->op2)->opcode == ZEND_QM_ASSIGN &&
+ ZEND_OP1_TYPE(VAR_SOURCE(opline->op2)) == IS_CONST) {
+ zend_op *src = VAR_SOURCE(opline->op2);
+ VAR_UNSET(opline->op2);
+ COPY_NODE(opline->op2, src->op1);
+ MAKE_NOP(src);
+ }
+
+ /* T = PRINT(X), F(T) => ECHO(X), F(1) */
+ if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_PRINT &&
+ opline->opcode != ZEND_CASE && opline->opcode != ZEND_FREE) {
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+ LITERAL_LONG(opline->op1, 1);
+ }
+
+ if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op2) &&
+ VAR_SOURCE(opline->op2)->opcode == ZEND_PRINT) {
+ ZEND_OP2_TYPE(opline) = IS_CONST;
+ LITERAL_LONG(opline->op2, 1);
+ }
+
+ /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
+ if ((opline->opcode == ZEND_ECHO || opline->opcode == ZEND_PRINT) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
+ VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ }
+
+ /* T = PRINT(X), FREE(T) => ECHO(X) */
+ if (opline->opcode == ZEND_FREE &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1)) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ if (src->opcode == ZEND_PRINT) {
+ src->opcode = ZEND_ECHO;
+ ZEND_RESULT_TYPE(src) = IS_UNUSED;
+ MAKE_NOP(opline);
+ }
+ }
+
+ /* T = BOOL(X), FREE(T) => NOP */
+ if (opline->opcode == ZEND_FREE &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1)) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ if (src->opcode == ZEND_BOOL) {
+ if (ZEND_OP1_TYPE(src) == IS_CONST) {
+ literal_dtor(&ZEND_OP1_LITERAL(src));
+ }
+ MAKE_NOP(src);
+ MAKE_NOP(opline);
+ }
+ }
+
+#if 0
+ /* pre-evaluate functions:
+ constant(x)
+ defined(x)
+ function_exists(x)
+ extension_loaded(x)
+ BAD: interacts badly with Accelerator
+ */
+ if((ZEND_OP1_TYPE(opline) & IS_VAR) &&
+ VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL &&
+ VAR_SOURCE(opline->op1)->extended_value == 1) {
+ zend_op *fcall = VAR_SOURCE(opline->op1);
+ zend_op *sv = fcall-1;
+ if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL &&
+ ZEND_OP1_TYPE(sv) == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING &&
+ Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1
+ ) {
+ zval *arg = &OPLINE_OP1_LITERAL(sv);
+ char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name;
+ int flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len;
+ if(flen == sizeof("defined")-1 && zend_binary_strcasecmp(fname, flen, "defined", sizeof("defined")-1) == 0) {
+ zval c;
+ if(zend_get_persistent_constant(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &c, 0 TSRMLS_CC ELS_CC) != 0) {
+ literal_dtor(arg);
+ MAKE_NOP(sv);
+ MAKE_NOP(fcall);
+ LITERAL_BOOL(opline->op1, 1);
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+ }
+ } else if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) ||
+ (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0)
+ ) {
+ zend_function *function;
+ if(zend_hash_find(EG(function_table), Z_STRVAL_P(arg), Z_STRLEN_P(arg)+1, (void **)&function) == SUCCESS) {
+ literal_dtor(arg);
+ MAKE_NOP(sv);
+ MAKE_NOP(fcall);
+ LITERAL_BOOL(opline->op1, 1);
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+ }
+ } else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) {
+ zval c;
+ if(zend_get_persistent_constant(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &c, 1 TSRMLS_CC ELS_CC) != 0) {
+ literal_dtor(arg);
+ MAKE_NOP(sv);
+ MAKE_NOP(fcall);
+ ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c TSRMLS_CC);
+ /* no copy ctor - get already copied it */
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+ }
+ } else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) {
+ if(zend_hash_exists(&module_registry, Z_STRVAL_P(arg), Z_STRLEN_P(arg)+1)) {
+ literal_dtor(arg);
+ MAKE_NOP(sv);
+ MAKE_NOP(fcall);
+ LITERAL_BOOL(opline->op1, 1);
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+ }
+ }
+ }
+ }
+#endif
+
+ /* IS_EQ(TRUE, X) => BOOL(X)
+ * IS_EQ(FALSE, X) => BOOL_NOT(X)
+ * IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
+ * IS_NOT_EQ(FALSE, X) => BOOL(X)
+ */
+ if (opline->opcode == ZEND_IS_EQUAL ||
+ opline->opcode == ZEND_IS_NOT_EQUAL) {
+ if (ZEND_OP1_TYPE(opline) == IS_CONST &&
+ Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_BOOL) {
+ opline->opcode =
+ ((opline->opcode == ZEND_IS_EQUAL) == Z_LVAL(ZEND_OP1_LITERAL(opline)))?
+ ZEND_BOOL : ZEND_BOOL_NOT;
+ COPY_NODE(opline->op1, opline->op2);
+ SET_UNUSED(opline->op2);
+ } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
+ Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_BOOL) {
+ opline->opcode =
+ ((opline->opcode == ZEND_IS_EQUAL) == Z_LVAL(ZEND_OP2_LITERAL(opline)))?
+ ZEND_BOOL : ZEND_BOOL_NOT;
+ SET_UNUSED(opline->op2);
+ }
+ }
+
+ if ((opline->opcode == ZEND_BOOL ||
+ opline->opcode == ZEND_BOOL_NOT ||
+ opline->opcode == ZEND_JMPZ ||
+ opline->opcode == ZEND_JMPNZ ||
+ opline->opcode == ZEND_JMPZNZ) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) != NULL &&
+ !used_ext[VAR_NUM(ZEND_OP1(opline).var)] &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT) {
+ /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+
+ COPY_NODE(opline->op1, src->op1);
+
+ switch (opline->opcode) {
+ case ZEND_BOOL:
+ /* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
+ opline->opcode = ZEND_BOOL_NOT;
+ break;
+ case ZEND_BOOL_NOT:
+ /* T = BOOL_NOT(X) + BOOL_BOOL(T) -> NOP, BOOL(X) */
+ opline->opcode = ZEND_BOOL;
+ break;
+ case ZEND_JMPZ:
+ /* T = BOOL_NOT(X) + JMPZ(T,L) -> NOP, JMPNZ(X,L) */
+ opline->opcode = ZEND_JMPNZ;
+ break;
+ case ZEND_JMPNZ:
+ /* T = BOOL_NOT(X) + JMPNZ(T,L) -> NOP, JMPZ(X,L) */
+ opline->opcode = ZEND_JMPZ;
+ break;
+ case ZEND_JMPZNZ:
+ {
+ /* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
+ int op_t;
+ zend_code_block *op_b;
+
+ op_t = opline->extended_value;
+ opline->extended_value = ZEND_OP2(opline).opline_num;
+ ZEND_OP2(opline).opline_num = op_t;
+
+ op_b = block->ext_to;
+ block->ext_to = block->op2_to;
+ block->op2_to = op_b;
+ }
+ break;
+ }
+
+ VAR_UNSET(opline->op1);
+ MAKE_NOP(src);
+ continue;
+ } else
+#if 0
+ /* T = BOOL_NOT(X) + T = JMPZ_EX(T, X) -> T = BOOL_NOT(X), JMPNZ(X) */
+ if(0 && (opline->opcode == ZEND_JMPZ_EX ||
+ opline->opcode == ZEND_JMPNZ_EX) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) != NULL &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT &&
+ ZEND_OP1(opline).var == ZEND_RESULT(opline).var
+ ) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ if(opline->opcode == ZEND_JMPZ_EX) {
+ opline->opcode = ZEND_JMPNZ;
+ } else {
+ opline->opcode = ZEND_JMPZ;
+ }
+ COPY_NODE(opline->op1, src->op1);
+ SET_UNUSED(opline->result);
+ continue;
+ } else
+#endif
+ /* T = BOOL(X) + JMPZ(T) -> NOP, JMPZ(X) */
+ if ((opline->opcode == ZEND_BOOL ||
+ opline->opcode == ZEND_BOOL_NOT ||
+ opline->opcode == ZEND_JMPZ ||
+ opline->opcode == ZEND_JMPZ_EX ||
+ opline->opcode == ZEND_JMPNZ_EX ||
+ opline->opcode == ZEND_JMPNZ ||
+ opline->opcode == ZEND_JMPZNZ) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) != NULL &&
+ (!used_ext[VAR_NUM(ZEND_OP1(opline).var)] ||
+ (ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
+ ZEND_RESULT(opline).var == ZEND_OP1(opline).var)) &&
+ (VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN)) {
+ zend_op *src = VAR_SOURCE(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+
+ VAR_UNSET(opline->op1);
+ MAKE_NOP(src);
+ continue;
+ } else if (last_op && opline->opcode == ZEND_ECHO &&
+ last_op->opcode == ZEND_ECHO &&
+ ZEND_OP1_TYPE(opline) == IS_CONST &&
+ Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
+ ZEND_OP1_TYPE(last_op) == IS_CONST &&
+ Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
+ /* compress consecutive ECHO's.
+ * Float to string conversion may be affected by current
+ * locale setting.
+ */
+ int l;
+
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
+ convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
+ }
+ if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
+ convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
+ }
+ l = Z_STRLEN(ZEND_OP1_LITERAL(opline)) + Z_STRLEN(ZEND_OP1_LITERAL(last_op));
+ if (IS_INTERNED(Z_STRVAL(ZEND_OP1_LITERAL(last_op)))) {
+ char *tmp = emalloc(l + 1);
+ memcpy(tmp, Z_STRVAL(ZEND_OP1_LITERAL(last_op)), l + 1);
+ Z_STRVAL(ZEND_OP1_LITERAL(last_op)) = tmp;
+ } else {
+ Z_STRVAL(ZEND_OP1_LITERAL(last_op)) = erealloc(Z_STRVAL(ZEND_OP1_LITERAL(last_op)), l + 1);
+ }
+ memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op))+Z_STRLEN(ZEND_OP1_LITERAL(last_op)), Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
+ Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
+ zval_dtor(&ZEND_OP1_LITERAL(opline));
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ Z_STRVAL(ZEND_OP1_LITERAL(opline)) = (char*)zend_new_interned_string(Z_STRVAL(ZEND_OP1_LITERAL(last_op)), l + 1, 1 TSRMLS_CC);
+ Z_TYPE(ZEND_OP1_LITERAL(last_op)) = IS_NULL;
+#else
+ Z_STRVAL(ZEND_OP1_LITERAL(opline)) = Z_STRVAL(ZEND_OP1_LITERAL(last_op));
+#endif
+ Z_STRLEN(ZEND_OP1_LITERAL(opline)) = l;
+ MAKE_NOP(last_op);
+ } else if (opline->opcode == ZEND_CONCAT &&
+ ZEND_OP2_TYPE(opline) == IS_CONST &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ (VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_ADD_STRING) &&
+ ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
+ ZEND_RESULT(VAR_SOURCE(opline->op1)).var == ZEND_OP1(opline).var) {
+ /* compress consecutive CONCATs */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ int l;
+
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
+ convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
+ }
+ if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
+ convert_to_string_safe(&ZEND_OP2_LITERAL(src));
+ }
+
+ VAR_UNSET(opline->op1);
+ if (ZEND_OP1_TYPE(src) == IS_UNUSED) {
+ /* 5.3 may use IS_UNUSED as first argument to ZEND_ADD_... */
+ opline->opcode = ZEND_ADD_STRING;
+ }
+ COPY_NODE(opline->op1, src->op1);
+ l = Z_STRLEN(ZEND_OP2_LITERAL(opline)) + Z_STRLEN(ZEND_OP2_LITERAL(src));
+ if (IS_INTERNED(Z_STRVAL(ZEND_OP2_LITERAL(src)))) {
+ char *tmp = emalloc(l + 1);
+ memcpy(tmp, Z_STRVAL(ZEND_OP2_LITERAL(src)), l + 1);
+ Z_STRVAL(ZEND_OP2_LITERAL(src)) = tmp;
+ } else {
+ Z_STRVAL(ZEND_OP2_LITERAL(src)) = erealloc(Z_STRVAL(ZEND_OP2_LITERAL(src)), l + 1);
+ }
+ memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src))+Z_STRLEN(ZEND_OP2_LITERAL(src)), Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
+ Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
+ if (!IS_INTERNED(Z_STRVAL(ZEND_OP2_LITERAL(opline)))) {
+ efree(Z_STRVAL(ZEND_OP2_LITERAL(opline)));
+ }
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ Z_STRVAL(ZEND_OP2_LITERAL(opline)) = (char*)zend_new_interned_string(Z_STRVAL(ZEND_OP2_LITERAL(src)), l + 1, 1 TSRMLS_CC);
+ Z_TYPE(ZEND_OP2_LITERAL(src)) = IS_NULL;
+#else
+ Z_STRVAL(ZEND_OP2_LITERAL(opline)) = Z_STRVAL(ZEND_OP2_LITERAL(src));
+#endif
+ Z_STRLEN(ZEND_OP2_LITERAL(opline)) = l;
+ MAKE_NOP(src);
+ } else if ((opline->opcode == ZEND_ADD_STRING || opline->opcode == ZEND_ADD_VAR) && ZEND_OP1_TYPE(opline) == IS_CONST) {
+ /* convert ADD_STRING(C1, C2) to CONCAT(C1, C2) */
+ opline->opcode = ZEND_CONCAT;
+ continue;
+ } else if (opline->opcode == ZEND_ADD_CHAR && ZEND_OP1_TYPE(opline) == IS_CONST && ZEND_OP2_TYPE(opline) == IS_CONST) {
+ /* convert ADD_CHAR(C1, C2) to CONCAT(C1, C2) */
+ char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
+ ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1, 1);
+ opline->opcode = ZEND_CONCAT;
+ continue;
+ } else if ((opline->opcode == ZEND_ADD ||
+ opline->opcode == ZEND_SUB ||
+ opline->opcode == ZEND_MUL ||
+ opline->opcode == ZEND_DIV ||
+ opline->opcode == ZEND_MOD ||
+ opline->opcode == ZEND_SL ||
+ opline->opcode == ZEND_SR ||
+ opline->opcode == ZEND_CONCAT ||
+ opline->opcode == ZEND_IS_EQUAL ||
+ opline->opcode == ZEND_IS_NOT_EQUAL ||
+ opline->opcode == ZEND_IS_SMALLER ||
+ opline->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
+ opline->opcode == ZEND_IS_IDENTICAL ||
+ opline->opcode == ZEND_IS_NOT_IDENTICAL ||
+ opline->opcode == ZEND_BOOL_XOR ||
+ opline->opcode == ZEND_BW_OR ||
+ opline->opcode == ZEND_BW_AND ||
+ opline->opcode == ZEND_BW_XOR) &&
+ ZEND_OP1_TYPE(opline)==IS_CONST &&
+ ZEND_OP2_TYPE(opline)==IS_CONST) {
+ /* evaluate constant expressions */
+ int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode);
+ zval result;
+ int er;
+
+ if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
+ ((Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG &&
+ Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) ||
+ (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_DOUBLE &&
+ Z_DVAL(ZEND_OP2_LITERAL(opline)) == 0.0))) {
+ if (RESULT_USED(opline)) {
+ SET_VAR_SOURCE(opline);
+ }
+ opline++;
+ continue;
+ }
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline) TSRMLS_CC) == SUCCESS) {
+ PZ_SET_REFCOUNT_P(&result, 1);
+ PZ_UNSET_ISREF_P(&result);
+
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ ZEND_OP1_LITERAL(opline) = result;
+ SET_UNUSED(opline->op2);
+
+ opline->opcode = ZEND_QM_ASSIGN;
+ }
+ EG(error_reporting) = er;
+ } else if ((opline->opcode == ZEND_BOOL ||
+ opline->opcode == ZEND_BOOL_NOT ||
+ opline->opcode == ZEND_BW_NOT) && ZEND_OP1_TYPE(opline) == IS_CONST) {
+ /* evaluate constant unary ops */
+ unary_op_type unary_op = get_unary_op(opline->opcode);
+ zval result;
+
+ if (unary_op) {
+ unary_op(&result, &ZEND_OP1_LITERAL(opline) TSRMLS_CC);
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ } else {
+ /* BOOL */
+ result = ZEND_OP1_LITERAL(opline);
+ convert_to_boolean(&result);
+ }
+ PZ_SET_REFCOUNT_P(&result, 1);
+ PZ_UNSET_ISREF_P(&result);
+ ZEND_OP1_LITERAL(opline) = result;
+ opline->opcode = ZEND_QM_ASSIGN;
+ } else if ((opline->opcode == ZEND_RETURN || opline->opcode == ZEND_EXIT) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN) {
+ /* T = QM_ASSIGN(X), RETURN(T) to RETURN(X) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ } else if ((opline->opcode == ZEND_ADD_STRING ||
+ opline->opcode == ZEND_ADD_CHAR) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) {
+ /* convert T = INIT_STRING(), T = ADD_STRING(T, X) to T = QM_ASSIGN(X) */
+ /* CHECKME: Remove ZEND_ADD_VAR optimization, since some conversions -
+ namely, BOOL(false)->string - don't allocate memory but use empty_string
+ and ADD_CHAR fails */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, opline->op2);
+ if (opline->opcode == ZEND_ADD_CHAR) {
+ char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
+ ZVAL_STRINGL(&ZEND_OP1_LITERAL(opline), &c, 1, 1);
+ }
+ SET_UNUSED(opline->op2);
+ MAKE_NOP(src);
+ opline->opcode = ZEND_QM_ASSIGN;
+ } else if ((opline->opcode == ZEND_ADD_STRING ||
+ opline->opcode == ZEND_ADD_CHAR ||
+ opline->opcode == ZEND_ADD_VAR ||
+ opline->opcode == ZEND_CONCAT) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT &&
+ ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
+ Z_TYPE(ZEND_OP2_LITERAL(VAR_SOURCE(opline->op1))) == IS_STRING &&
+ Z_STRLEN(ZEND_OP2_LITERAL(VAR_SOURCE(opline->op1))) == 0) {
+ /* convert T = CONCAT(X,''), T = ADD_STRING(T, Y) to T = CONCAT(X,Y) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+ if (opline->opcode == ZEND_ADD_CHAR) {
+ char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
+ ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1, 1);
+ }
+ opline->opcode = ZEND_CONCAT;
+ literal_dtor(&ZEND_OP2_LITERAL(src)); /* will take care of empty_string too */
+ MAKE_NOP(src);
+ } else if (opline->opcode == ZEND_ADD_VAR &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) {
+ /* convert T = INIT_STRING(), T = ADD_VAR(T, X) to T = CAST(STRING, X) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, opline->op2);
+ SET_UNUSED(opline->op2);
+ MAKE_NOP(src);
+ opline->opcode = ZEND_CAST;
+ opline->extended_value = IS_STRING;
+ } else if ((opline->opcode == ZEND_ADD_STRING ||
+ opline->opcode == ZEND_ADD_CHAR ||
+ opline->opcode == ZEND_ADD_VAR ||
+ opline->opcode == ZEND_CONCAT) &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
+ VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
+ /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ VAR_UNSET(opline->op1);
+ COPY_NODE(opline->op1, src->op1);
+ if (opline->opcode == ZEND_ADD_CHAR) {
+ char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
+ ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1, 1);
+ }
+ opline->opcode = ZEND_CONCAT;
+ MAKE_NOP(src);
+ } else if (opline->opcode == ZEND_QM_ASSIGN &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
+ ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
+ /* strip T = QM_ASSIGN(T) */
+ MAKE_NOP(opline);
+ } else if (opline->opcode == ZEND_BOOL &&
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ VAR_SOURCE(opline->op1) &&
+ (VAR_SOURCE(opline->op1)->opcode == ZEND_IS_EQUAL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_EQUAL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_IS_IDENTICAL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_VAR ||
+ VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) &&
+ !used_ext[VAR_NUM(ZEND_OP1(opline).var)]) {
+ /* T = IS_SMALLER(X, Y), T1 = BOOL(T) => T = IS_SMALLER(X, Y), T1 = QM_ASSIGN(T) */
+ zend_op *src = VAR_SOURCE(opline->op1);
+ COPY_NODE(src->result, opline->result);
+ SET_VAR_SOURCE(src);
+ MAKE_NOP(opline);
+ }
+ /* get variable source */
+ if (RESULT_USED(opline)) {
+ SET_VAR_SOURCE(opline);
+ }
+ if (opline->opcode != ZEND_NOP) {
+ last_op = opline;
+ }
+ opline++;
+ }
+
+ /* remove leading NOPs */
+ while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
+ if (block->len == 1) {
+ /* this block is all NOPs, join with following block */
+ if (block->follow_to) {
+ delete_code_block(block);
+ }
+ if (op_array->T) {
+ efree(Tsource);
+ }
+ return;
+ }
+ block->start_opline++;
+ block->start_opline_no++;
+ block->len--;
+ }
+
+ /* strip the inside NOPs */
+ opline = block->start_opline;
+ end = opline + block->len;
+ while (opline < end) {
+ if (opline->opcode == ZEND_NOP) {
+ zend_op *nop = opline + 1;
+ int noplen;
+ while (nop < end && nop->opcode == ZEND_NOP) {
+ nop++;
+ }
+ noplen = nop-opline;
+ if (nop < end) {
+ /* move up non-NOP opcodes */
+ memmove(opline, nop, (end-nop)*sizeof(zend_op));
+ } else {
+ /* all NOPs up to the end, do nothing */
+ }
+ block->len -= noplen;
+ end = block->start_opline + block->len;
+ }
+ opline++;
+ }
+
+ if (op_array->T) {
+ efree(Tsource);
+ }
+}
+
+/* Rebuild plain (optimized) op_array from CFG */
+static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
+{
+ zend_code_block *blocks = cfg->blocks;
+ zend_op *new_opcodes = emalloc(op_array->last * sizeof(zend_op));
+ zend_op *opline = new_opcodes;
+ zend_code_block *cur_block = blocks;
+
+ /* Copy code of reachable blocks into a single buffer */
+ while (cur_block) {
+ if (cur_block->access) {
+ memcpy(opline, cur_block->start_opline, cur_block->len * sizeof(zend_op));
+ cur_block->start_opline = opline;
+ opline += cur_block->len;
+ if ((opline - 1)->opcode == ZEND_JMP) {
+ zend_code_block *next;
+ next = cur_block->next;
+ while (next && !next->access) {
+ next = next->next;
+ }
+ if (next && next == cur_block->op1_to) {
+ /* JMP to the next block - strip it */
+ cur_block->follow_to = cur_block->op1_to;
+ cur_block->op1_to = NULL;
+ MAKE_NOP((opline - 1));
+ opline--;
+ cur_block->len--;
+ }
+ }
+ } else {
+ /* this block will not be used, delete all constants there */
+ zend_op *_opl;
+ zend_op *end = cur_block->start_opline + cur_block->len;
+ for (_opl = cur_block->start_opline; _opl && _opl < end; _opl++) {
+ if (ZEND_OP1_TYPE(_opl) == IS_CONST) {
+ literal_dtor(&ZEND_OP1_LITERAL(_opl));
+ }
+ if (ZEND_OP2_TYPE(_opl) == IS_CONST) {
+ literal_dtor(&ZEND_OP2_LITERAL(_opl));
+ }
+ }
+ }
+ cur_block = cur_block->next;
+ }
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ if (opline[-1].opcode == ZEND_THROW) {
+ /* if we finished with THROW, we need to add space between THROW and HANDLE to not confuse
+ zend_throw_internal */
+ MAKE_NOP(opline);
+ opline->lineno = opline[-1].lineno;
+ opline++;
+ }
+ MAKE_NOP(opline);
+ opline->opcode = ZEND_HANDLE_EXCEPTION;
+ opline->lineno = opline[-1].lineno;
+ opline++;
+#endif
+
+ op_array->last = opline-new_opcodes;
+
+ /* adjust exception jump targets */
+ if (op_array->last_try_catch) {
+ int i;
+ for (i = 0; i< op_array->last_try_catch; i++) {
+ op_array->try_catch_array[i].try_op = cfg->try[i]->start_opline - new_opcodes;
+ op_array->try_catch_array[i].catch_op = cfg->catch[i]->start_opline - new_opcodes;
+ }
+ efree(cfg->try);
+ efree(cfg->catch);
+ }
+
+ /* adjust loop jump targets */
+ if (op_array->last_brk_cont) {
+ int i;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ op_array->brk_cont_array[i].start = cfg->loop_start[i]->start_opline - new_opcodes;
+ op_array->brk_cont_array[i].cont = cfg->loop_cont[i]->start_opline - new_opcodes;
+ op_array->brk_cont_array[i].brk = cfg->loop_brk[i]->start_opline - new_opcodes;
+ }
+ efree(cfg->loop_start);
+ efree(cfg->loop_cont);
+ efree(cfg->loop_brk);
+ }
+
+ /* adjust jump targets */
+ for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
+ if (!cur_block->access) {
+ continue;
+ }
+ if (cur_block->op1_to) {
+ ZEND_OP1(&cur_block->start_opline[cur_block->len - 1]).opline_num = cur_block->op1_to->start_opline - new_opcodes;
+ }
+ if (cur_block->op2_to) {
+ ZEND_OP2(&cur_block->start_opline[cur_block->len - 1]).opline_num = cur_block->op2_to->start_opline - new_opcodes;
+ }
+ if (cur_block->ext_to) {
+ cur_block->start_opline[cur_block->len - 1].extended_value = cur_block->ext_to->start_opline - new_opcodes;
+ }
+ print_block(cur_block, new_opcodes, "Out ");
+ }
+ efree(op_array->opcodes);
+ op_array->opcodes = erealloc(new_opcodes, op_array->last * sizeof(zend_op));
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ /* adjust early binding list */
+ if (op_array->early_binding != (zend_uint)-1) {
+ zend_uint *opline_num = &op_array->early_binding;
+ zend_op *end;
+
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+ if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
+ *opline_num = opline - op_array->opcodes;
+ opline_num = &ZEND_RESULT(opline).opline_num;
+ }
+ ++opline;
+ }
+ *opline_num = -1;
+ }
+#endif
+}
+
+static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_array, zend_code_block *blocks)
+{
+ /* last_op is the last opcode of the current block */
+ zend_op *last_op = (block->start_opline + block->len - 1);
+
+ if (!block->len) {
+ return;
+ }
+ switch (last_op->opcode) {
+ case ZEND_JMP:
+ {
+ zend_op *target = block->op1_to->start_opline;
+ zend_code_block *next = block->next;
+
+ while (next && !next->access) {
+ /* find used one */
+ next = next->next;
+ }
+
+ /* JMP(next) -> NOP */
+ if (block->op1_to == next) {
+ block->follow_to = block->op1_to;
+ block->op1_to = NULL;
+ MAKE_NOP(last_op);
+ block->len--;
+ if (block->len == 0) {
+ /* this block is nothing but NOP now */
+ delete_code_block(block);
+ }
+ break;
+ }
+
+ if (((target->opcode == ZEND_JMP &&
+ block->op1_to != block->op1_to->op1_to) ||
+ target->opcode == ZEND_JMPZNZ) &&
+ !block->op1_to->protected) {
+ /* JMP L, L: JMP L1 -> JMP L1 */
+ /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
+ *last_op = *target;
+#if ZEND_EXTENSION_API_NO < PHP_5_4_X_API_NO
+ if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
+ zval_copy_ctor(&ZEND_OP1_LITERAL(last_op));
+ }
+#endif
+ del_source(block, block->op1_to);
+ if (block->op1_to->op2_to) {
+ block->op2_to = block->op1_to->op2_to;
+ ADD_SOURCE(block, block->op2_to);
+ }
+ if (block->op1_to->ext_to) {
+ block->ext_to = block->op1_to->ext_to;
+ ADD_SOURCE(block, block->ext_to);
+ }
+ if (block->op1_to->op1_to) {
+ block->op1_to = block->op1_to->op1_to;
+ ADD_SOURCE(block, block->op1_to);
+ } else {
+ block->op1_to = NULL;
+ }
+ } else if (target->opcode == ZEND_RETURN ||
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ target->opcode == ZEND_RETURN_BY_REF ||
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ target->opcode == ZEND_FAST_RET ||
+#endif
+ target->opcode == ZEND_EXIT) {
+ /* JMP L, L: RETURN to immediate RETURN */
+ *last_op = *target;
+#if ZEND_EXTENSION_API_NO < PHP_5_4_X_API_NO
+ if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
+ zval_copy_ctor(&ZEND_OP1_LITERAL(last_op));
+ }
+#endif
+ del_source(block, block->op1_to);
+ block->op1_to = NULL;
+#if 0
+ /* Temporarily disabled - see bug #0025274 */
+ } else if (0&& block->op1_to != block &&
+ block->op1_to != blocks &&
+ op_array->last_try_catch == 0 &&
+ target->opcode != ZEND_FREE &&
+ target->opcode != ZEND_SWITCH_FREE) {
+ /* Block Reordering (saves one JMP on each "for" loop iteration)
+ * It is disabled for some cases (ZEND_FREE/ZEND_SWITCH_FREE)
+ * which may break register allocation.
+ */
+ zend_bool can_reorder = 0;
+ zend_block_source *cs = block->op1_to->sources;
+
+ /* the "target" block doesn't had any followed block */
+ while(cs) {
+ if (cs->from->follow_to == block->op1_to) {
+ can_reorder = 0;
+ break;
+ }
+ cs = cs->next;
+ }
+ if (can_reorder) {
+ next = block->op1_to;
+ /* the "target" block is not followed by current "block" */
+ while (next->follow_to != NULL) {
+ if (next->follow_to == block) {
+ can_reorder = 0;
+ break;
+ }
+ next = next->follow_to;
+ }
+ if (can_reorder) {
+ zend_code_block *prev = blocks;
+
+ while (prev->next != block->op1_to) {
+ prev = prev->next;
+ }
+ prev->next = next->next;
+ next->next = block->next;
+ block->next = block->op1_to;
+
+ block->follow_to = block->op1_to;
+ block->op1_to = NULL;
+ MAKE_NOP(last_op);
+ block->len--;
+ if(block->len == 0) {
+ /* this block is nothing but NOP now */
+ delete_code_block(block);
+ }
+ break;
+ }
+ }
+#endif
+ }
+ }
+ break;
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ /* constant conditional JMPs */
+ if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
+ int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
+ if (last_op->opcode == ZEND_JMPZ) {
+ should_jmp = !should_jmp;
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(last_op));
+ ZEND_OP1_TYPE(last_op) = IS_UNUSED;
+ if (should_jmp) {
+ /* JMPNZ(true) -> JMP */
+ last_op->opcode = ZEND_JMP;
+ COPY_NODE(last_op->op1, last_op->op2);
+ block->op1_to = block->op2_to;
+ del_source(block, block->follow_to);
+ block->op2_to = NULL;
+ block->follow_to = NULL;
+ } else {
+ /* JMPNZ(false) -> NOP */
+ MAKE_NOP(last_op);
+ del_source(block, block->op2_to);
+ block->op2_to = NULL;
+ }
+ break;
+ }
+
+ if (block->op2_to) {
+ zend_uchar same_type = ZEND_OP1_TYPE(last_op);
+ zend_uint same_var = VAR_NUM_EX(last_op->op1);
+ zend_op *target;
+ zend_op *target_end;
+ zend_code_block *target_block = block->op2_to;;
+
+next_target:
+ target = target_block->start_opline;
+ target_end = target_block->start_opline + target_block->len;
+ while (target < target_end && target->opcode == ZEND_NOP) {
+ target++;
+ }
+
+ /* next block is only NOP's */
+ if (target == target_end) {
+ target_block = target_block->follow_to;
+ goto next_target;
+ } else if (target->opcode == INV_COND(last_op->opcode) &&
+ /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ target_block->follow_to &&
+ !target_block->protected
+ ) {
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->follow_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target->opcode == INV_COND_EX(last_op->opcode) &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ target_block->follow_to &&
+ !target_block->protected) {
+ /* JMPZ(X, L), L: X = JMPNZ_EX(X, L2) -> JMPZ(X, L+1) */
+ last_op->opcode += 3;
+ last_op->result = target->result;
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->follow_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target->opcode == last_op->opcode &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ !target_block->protected) {
+ /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op2_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op1_to &&
+ target->opcode == ZEND_JMP &&
+ !target_block->protected) {
+ /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op1_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target_block->ext_to &&
+ target->opcode == ZEND_JMPZNZ &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ !target_block->protected) {
+ /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
+ del_source(block, block->op2_to);
+ if (last_op->opcode == ZEND_JMPZ) {
+ block->op2_to = target_block->op2_to;
+ } else {
+ block->op2_to = target_block->ext_to;
+ }
+ ADD_SOURCE(block, block->op2_to);
+ }
+ }
+
+ if (block->follow_to &&
+ (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ)) {
+ zend_op *target;
+ zend_op *target_end;
+
+ while (1) {
+ target = block->follow_to->start_opline;
+ target_end = block->follow_to->start_opline + block->follow_to->len;
+ while (target < target_end && target->opcode == ZEND_NOP) {
+ target++;
+ }
+
+ /* next block is only NOP's */
+ if (target == target_end) {
+ del_source(block, block->follow_to);
+ block->follow_to = block->follow_to->follow_to;
+ ADD_SOURCE(block, block->follow_to);
+ } else {
+ break;
+ }
+ }
+ /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
+ if (target->opcode == ZEND_JMP &&
+ block->follow_to->op1_to &&
+ !block->follow_to->protected) {
+ del_source(block, block->follow_to);
+ if (last_op->opcode == ZEND_JMPZ) {
+ block->ext_to = block->follow_to->op1_to;
+ ADD_SOURCE(block, block->ext_to);
+ } else {
+ block->ext_to = block->op2_to;
+ block->op2_to = block->follow_to->op1_to;
+ ADD_SOURCE(block, block->op2_to);
+ }
+ block->follow_to = NULL;
+ last_op->opcode = ZEND_JMPZNZ;
+ }
+ }
+ break;
+
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMPZ_EX:
+ /* constant conditional JMPs */
+ if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
+ int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
+ if (last_op->opcode == ZEND_JMPZ_EX) {
+ should_jmp = !should_jmp;
+ }
+ if (!should_jmp) {
+ /* T = JMPZ_EX(true,L) -> T = QM_ASSIGN(true)
+ * T = JMPNZ_EX(false,L) -> T = QM_ASSIGN(false)
+ */
+ last_op->opcode = ZEND_QM_ASSIGN;
+ SET_UNUSED(last_op->op2);
+ del_source(block, block->op2_to);
+ block->op2_to = NULL;
+ }
+ break;
+ }
+
+ if (block->op2_to) {
+ zend_op *target, *target_end;
+ char *same_t=NULL;
+ zend_code_block *target_block;
+ int var_num = 0;
+ if (op_array->T >= (zend_uint)op_array->last_var) {
+ var_num = op_array->T;
+ } else {
+ var_num = op_array->last_var;
+ }
+ if (var_num <= 0) {
+ return;
+ }
+ same_t = ecalloc(var_num, sizeof(char));
+ if (same_t == NULL) {
+ return;
+ }
+ same_t[VAR_NUM_EX(last_op->op1)] |= ZEND_OP1_TYPE(last_op);
+ same_t[VAR_NUM_EX(last_op->result)] |= ZEND_RESULT_TYPE(last_op);
+ target_block = block->op2_to;
+next_target_ex:
+ target = target_block->start_opline;
+ target_end = target_block->start_opline + target_block->len;
+ while (target < target_end && target->opcode == ZEND_NOP) {
+ target++;
+ }
+ /* next block is only NOP's */
+ if (target == target_end) {
+ target_block = target_block->follow_to;
+ goto next_target_ex;
+ } else if (target_block->op2_to &&
+ target->opcode == last_op->opcode-3 &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op2_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target->opcode == INV_EX_COND(last_op->opcode) &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->follow_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target->opcode == INV_EX_COND_EX(last_op->opcode) &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
+ (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->follow_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target->opcode == last_op->opcode &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
+ (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op2_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op1_to &&
+ target->opcode == ZEND_JMP &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op1_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op2_to &&
+ target_block->ext_to &&
+ target->opcode == ZEND_JMPZNZ &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
+ !target_block->protected) {
+ /* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
+ del_source(block, block->op2_to);
+ if (last_op->opcode == ZEND_JMPZ_EX) {
+ block->op2_to = target_block->op2_to;
+ } else {
+ block->op2_to = target_block->ext_to;
+ }
+ ADD_SOURCE(block, block->op2_to);
+ }
+ if (same_t != NULL) {
+ efree(same_t);
+ }
+ }
+ break;
+
+ case ZEND_JMPZNZ: {
+ zend_code_block *next = block->next;
+
+ while (next && !next->access) {
+ /* find first accessed one */
+ next = next->next;
+ }
+
+ if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
+ if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
+ /* JMPZNZ(false,L1,L2) -> JMP(L1) */
+ zend_code_block *todel;
+
+ literal_dtor(&ZEND_OP1_LITERAL(last_op));
+ last_op->opcode = ZEND_JMP;
+ SET_UNUSED(last_op->op1);
+ SET_UNUSED(last_op->op2);
+ block->op1_to = block->op2_to;
+ todel = block->ext_to;
+ block->op2_to = NULL;
+ block->ext_to = NULL;
+ del_source(block, todel);
+ } else {
+ /* JMPZNZ(true,L1,L2) -> JMP(L2) */
+ zend_code_block *todel;
+
+ literal_dtor(&ZEND_OP1_LITERAL(last_op));
+ last_op->opcode = ZEND_JMP;
+ SET_UNUSED(last_op->op1);
+ SET_UNUSED(last_op->op2);
+ block->op1_to = block->ext_to;
+ todel = block->op2_to;
+ block->op2_to = NULL;
+ block->ext_to = NULL;
+ del_source(block, todel);
+ }
+ } else if (block->op2_to == block->ext_to) {
+ /* both goto the same one - it's JMP */
+ /* JMPZNZ(?,L,L) -> JMP(L) */
+ last_op->opcode = ZEND_JMP;
+ SET_UNUSED(last_op->op1);
+ SET_UNUSED(last_op->op2);
+ block->op1_to = block->op2_to;
+ block->op2_to = NULL;
+ block->ext_to = NULL;
+ } else if (block->op2_to == next) {
+ /* jumping to next on Z - can follow to it and jump only on NZ */
+ /* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
+ last_op->opcode = ZEND_JMPNZ;
+ block->op2_to = block->ext_to;
+ block->follow_to = next;
+ block->ext_to = NULL;
+ /* no need to add source - it's block->op2_to */
+ } else if (block->ext_to == next) {
+ /* jumping to next on NZ - can follow to it and jump only on Z */
+ /* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
+ last_op->opcode = ZEND_JMPZ;
+ block->follow_to = next;
+ block->ext_to = NULL;
+ /* no need to add source - it's block->ext_to */
+ }
+
+ if (last_op->opcode == ZEND_JMPZNZ && block->op2_to) {
+ zend_uchar same_type = ZEND_OP1_TYPE(last_op);
+ zend_uchar same_var = VAR_NUM_EX(last_op->op1);
+ zend_op *target;
+ zend_op *target_end;
+ zend_code_block *target_block = block->op2_to;
+
+next_target_znz:
+ target = target_block->start_opline;
+ target_end = target_block->start_opline + target_block->len;
+ while (target < target_end && target->opcode == ZEND_NOP) {
+ target++;
+ }
+ /* next block is only NOP's */
+ if (target == target_end) {
+ target_block = target_block->follow_to;
+ goto next_target_znz;
+ } else if (target_block->op2_to &&
+ (target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ !target_block->protected) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op2_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target->opcode == ZEND_JMPNZ &&
+ (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
+ same_type == ZEND_OP1_TYPE(target) &&
+ same_var == VAR_NUM_EX(target->op1) &&
+ target_block->follow_to &&
+ !target_block->protected) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->follow_to;
+ ADD_SOURCE(block, block->op2_to);
+ } else if (target_block->op1_to &&
+ target->opcode == ZEND_JMP &&
+ !target_block->protected) {
+ /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
+ del_source(block, block->op2_to);
+ block->op2_to = target_block->op1_to;
+ ADD_SOURCE(block, block->op2_to);
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* Global data dependencies */
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+
+# define T_USAGE(op) do { \
+ if ((op ## _type & (IS_VAR | IS_TMP_VAR)) && \
+ !defined_here[VAR_NUM(op.var)] && !used_ext[VAR_NUM(op.var)]) { \
+ used_ext[VAR_NUM(op.var)] = 1; \
+ } \
+ } while (0)
+
+# define NEVER_USED(op) ((op ## _type & (IS_VAR | IS_TMP_VAR)) && !usage[VAR_NUM(op.var)]) /* !used_ext[op.var] && */
+# define RES_NEVER_USED(opline) (opline->result_type == IS_UNUSED || NEVER_USED(opline->result))
+
+#else
+
+# define T_USAGE(op) do { \
+ if ((op.op_type == IS_VAR || op.op_type == IS_TMP_VAR) && \
+ !defined_here[VAR_NUM(op.u.var)] && !used_ext[VAR_NUM(op.u.var)]) { \
+ used_ext[VAR_NUM(op.u.var)] = 1; \
+ } \
+ } while (0)
+
+# define NEVER_USED(op) ((op.op_type == IS_VAR || op.op_type == IS_TMP_VAR) && !usage[VAR_NUM(op.u.var)]) /* !used_ext[op.u.var] && */
+# define RES_NEVER_USED(opline) (ZEND_RESULT_TYPE(opline) == IS_UNUSED || NEVER_USED(opline->result))
+
+#endif
+
+/* Find a set of variables which are used outside of the block where they are
+ * defined. We won't apply some optimization patterns for sush variables. */
+static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *used_ext)
+{
+ zend_code_block *next_block = block->next;
+ char *usage;
+ char *defined_here;
+
+ if (op_array->T == 0) {
+ /* shortcut - if no Ts, nothing to do */
+ return;
+ }
+
+ usage = ecalloc(op_array->T, 1);
+ defined_here = emalloc(op_array->T);
+
+ while (next_block) {
+ zend_op *opline = next_block->start_opline;
+ zend_op *end = opline + next_block->len;
+
+ if (!next_block->access) {
+ next_block = next_block->next;
+ continue;
+ }
+ memset(defined_here, 0, op_array->T);
+
+ while (opline<end) {
+ T_USAGE(opline->op1);
+ T_USAGE(opline->op2);
+
+ if (RESULT_USED(opline)) {
+ if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] &&
+ (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT ||
+ (opline->opcode == ZEND_OP_DATA && ZEND_RESULT_TYPE(opline) == IS_TMP_VAR) ||
+ opline->opcode == ZEND_ADD_ARRAY_ELEMENT)) {
+ /* these opcodes use the result as argument */
+ used_ext[VAR_NUM(ZEND_RESULT(opline).var)] = 1;
+ }
+ defined_here[VAR_NUM(ZEND_RESULT(opline).var)] = 1;
+ }
+ opline++;
+ }
+ next_block = next_block->next;
+ }
+
+#if DEBUG_BLOCKPASS
+ {
+ int i;
+ for (i = 0; i< op_array->T; i++) {
+ fprintf(stderr, "T%d: %c\n", i, used_ext[i] + '0');
+ }
+ }
+#endif
+
+ while (block) {
+ zend_op *opline = block->start_opline + block->len - 1;
+
+ if (!block->access) {
+ block = block->next;
+ continue;
+ }
+
+ memcpy(usage, used_ext, op_array->T);
+
+ while (opline >= block->start_opline) {
+ /* usage checks */
+ if (RES_NEVER_USED(opline)) {
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ case ZEND_ASSIGN_CONCAT:
+ case ZEND_ASSIGN_BW_OR:
+ case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ case ZEND_ASSIGN:
+ case ZEND_ASSIGN_REF:
+ case ZEND_DO_FCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ if (ZEND_RESULT_TYPE(opline) == IS_VAR) {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED;
+#else
+ ZEND_RESULT(opline).EA.type |= EXT_TYPE_UNUSED;
+#endif
+ }
+ break;
+ case ZEND_QM_ASSIGN:
+ case ZEND_BOOL:
+ case ZEND_BOOL_NOT:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ }
+ MAKE_NOP(opline);
+ break;
+ case ZEND_PRINT:
+ opline->opcode = ZEND_ECHO;
+ ZEND_RESULT_TYPE(opline) = IS_UNUSED;
+ break;
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ opline->opcode -= 3;
+ SET_UNUSED(opline->result);
+ break;
+ }
+ }
+
+ if (opline->opcode == ZEND_RECV ||
+ opline->opcode == ZEND_RECV_INIT ||
+ opline->opcode == ZEND_ADD_ARRAY_ELEMENT) {
+ if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) {
+ usage[VAR_NUM(ZEND_RESULT(opline).var)] = 1;
+ }
+ } else {
+ if (RESULT_USED(opline)) {
+ usage[VAR_NUM(ZEND_RESULT(opline).var)] = 0;
+ }
+ }
+
+ if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) {
+ usage[VAR_NUM(ZEND_OP1(opline).var)] = 1;
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_VAR || ZEND_OP2_TYPE(opline) == IS_TMP_VAR) {
+ usage[VAR_NUM(ZEND_OP2(opline).var)] = 1;
+ }
+
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if ((ZEND_RESULT_TYPE(opline) & IS_VAR) &&
+ (ZEND_RESULT_TYPE(opline) & EXT_TYPE_UNUSED) &&
+ usage[VAR_NUM(ZEND_RESULT(opline).var)]) {
+ ZEND_RESULT_TYPE(opline) &= ~EXT_TYPE_UNUSED;
+ }
+#else
+ if (ZEND_RESULT_TYPE(opline) == IS_VAR &&
+ usage[VAR_NUM(ZEND_RESULT(opline).var)] &&
+ (ZEND_RESULT(opline).EA.type & EXT_TYPE_UNUSED) != 0) {
+ ZEND_RESULT(opline).EA.type &= ~EXT_TYPE_UNUSED;
+ }
+#endif
+
+ opline--;
+ }
+ block = block->next;
+ } /* end blocks */
+
+ efree(defined_here);
+ efree(usage);
+}
+
+#define PASSES 3
+
+static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC)
+{
+ zend_cfg cfg;
+ zend_code_block *cur_block;
+ int pass;
+ char *usage;
+
+#if DEBUG_BLOCKPASS
+ fprintf(stderr, "File %s func %s\n", op_array->filename, op_array->function_name? op_array->function_name : "main");
+ fflush(stderr);
+#endif
+
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ return;
+ }
+#endif
+
+ /* Build CFG */
+ if (!find_code_blocks(op_array, &cfg)) {
+ return;
+ }
+
+ zend_rebuild_access_path(&cfg, op_array, 0);
+ /* full rebuild here to produce correct sources! */
+ usage = emalloc(op_array->T);
+ for (pass = 0; pass < PASSES; pass++) {
+ /* Compute data dependencies */
+ memset(usage, 0, op_array->T);
+ zend_t_usage(cfg.blocks, op_array, usage);
+
+ /* optimize each basic block separately */
+ for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
+ if (!cur_block->access) {
+ continue;
+ }
+ zend_optimize_block(cur_block, op_array, usage TSRMLS_CC);
+ }
+
+ /* Jump optimization for each block */
+ for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
+ if (!cur_block->access) {
+ continue;
+ }
+ zend_jmp_optimization(cur_block, op_array, cfg.blocks);
+ }
+
+ /* Eliminate unreachable basic blocks */
+ zend_rebuild_access_path(&cfg, op_array, 1);
+ }
+
+ memset(usage, 0, op_array->T);
+ zend_t_usage(cfg.blocks, op_array, usage);
+ assemble_code_blocks(&cfg, op_array);
+ efree(usage);
+
+ /* Destroy CFG */
+ for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
+ zend_block_source *cs = cur_block->sources;
+ while (cs) {
+ zend_block_source *n = cs->next;
+ efree(cs);
+ cs = n;
+ }
+ }
+ efree(cfg.blocks);
+}
diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c
new file mode 100644
index 000000000..b2fb667ed
--- /dev/null
+++ b/ext/opcache/Optimizer/nop_removal.c
@@ -0,0 +1,126 @@
+/* pass 10:
+ * - remove NOPs
+ */
+
+static void nop_removal(zend_op_array *op_array)
+{
+ zend_op *end, *opline;
+ zend_uint new_count, i, shift;
+ int j;
+ zend_uint *shiftlist;
+ ALLOCA_FLAG(use_heap);
+
+ shiftlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint) * op_array->last);
+ i = new_count = shift = 0;
+ end = op_array->opcodes + op_array->last;
+ for (opline = op_array->opcodes; opline < end; opline++) {
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ /* GOTO target is unresolved yet. We can't optimize. */
+ if (opline->opcode == ZEND_GOTO &&
+ Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* TODO: in general we can avoid this restriction */
+ FREE_ALLOCA(shiftlist);
+ return;
+ }
+#endif
+
+ /* Kill JMP-over-NOP-s */
+ if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
+ /* check if there are only NOPs under the branch */
+ zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 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) {
+ op_array->opcodes[new_count] = *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++) {
+ switch (opline->opcode) {
+ case ZEND_JMP:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_GOTO:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+#endif
+ ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num];
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_FE_FETCH:
+ case ZEND_FE_RESET:
+ case ZEND_NEW:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
+ break;
+ case ZEND_JMPZNZ:
+ ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
+ opline->extended_value -= shiftlist[opline->extended_value];
+ break;
+ case ZEND_CATCH:
+ opline->extended_value -= shiftlist[opline->extended_value];
+ break;
+ }
+ }
+
+ /* update brk/cont array */
+ for (j = 0; j < op_array->last_brk_cont; j++) {
+ op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk];
+ op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont];
+ op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start];
+ }
+
+ /* 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 ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ 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];
+ }
+#endif
+ }
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ /* update early binding list */
+ if (op_array->early_binding != (zend_uint)-1) {
+ zend_uint *opline_num = &op_array->early_binding;
+
+ do {
+ *opline_num -= shiftlist[*opline_num];
+ opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num;
+ } while (*opline_num != (zend_uint)-1);
+ }
+#endif
+ }
+ FREE_ALLOCA(shiftlist);
+}
diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c
new file mode 100644
index 000000000..dc630733f
--- /dev/null
+++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c
@@ -0,0 +1,222 @@
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+
+/* ops that use CLs:
+op1:
+ZEND_FETCH_CONSTANT:
+ZEND_INIT_CTOR_CALL:
+ZEND_INIT_STATIC_METHOD_CALL:
+ZEND_INIT_METHOD_CALL:
+ZEND_IMPORT_CLASS:
+ZEND_IMPORT_FUNCTION:
+ZEND_IMPORT_CONST:
+ZEND_ADD_INTERFACE:
+ZEND_VERIFY_ABSTRACT_CLASS:
+ZEND_NEW:
+ZEND_CATCH:
+ZEND_INIT_FCALL_BY_NAME:
+
+op2:
+ZEND_UNSET_VAR:
+ZEND_ISSET_ISEMPTY_VAR:
+ZEND_FETCH_UNSET:
+ZEND_FETCH_IS:
+ZEND_FETCH_R:
+ZEND_FETCH_W:
+ZEND_FETCH_RW:
+ZEND_FETCH_FUNC_ARG:
+ZEND_ADD_INTERFACE:
+ZEND_INSTANCEOF:
+
+extended_value:
+ZEND_DECLARE_INHERITED_CLASS:
+
+ignore result
+INIT_METHOD_CALL:
+*/
+
+#define OP1_CONST_IS_CLASS 1
+#define OP2_CONST_IS_CLASS 2
+#define EXT_CONST_IS_CLASS 4
+#define RESULT_IS_UNUSED 8
+
+static const char op_const_means_class[256] = {
+ /* 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ /* 64 */
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2,
+ /* 96 */
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 128 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 192 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 224 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+#endif
+
+#define GET_AVAILABLE_T() \
+ for (i = 0; i < T; i++) { \
+ if (!taken_T[i]) { \
+ break; \
+ } \
+ } \
+ taken_T[i] = 1; \
+ if (i > max) { \
+ max = i; \
+ }
+
+static void optimize_temporary_variables(zend_op_array *op_array)
+{
+ int T = op_array->T;
+ char *taken_T; /* T index in use */
+ zend_op **start_of_T; /* opline where T is first used */
+ char *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;
+ int var_to_free = -1;
+
+ taken_T = (char *) emalloc(T);
+ start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *));
+ valid_T = (char *) emalloc(T);
+ map_T = (int *) emalloc(T * sizeof(int));
+
+ end = op_array->opcodes;
+ opline = &op_array->opcodes[op_array->last - 1];
+
+ /* Find T definition points */
+ while (opline >= end) {
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
+ if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
+ start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
+ }
+ }
+#else
+ if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
+ start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
+ }
+#endif
+ opline--;
+ }
+
+ memset(valid_T, 0, T);
+ memset(taken_T, 0, T);
+
+ end = op_array->opcodes;
+ opline = &op_array->opcodes[op_array->last - 1];
+
+ while (opline >= end) {
+ if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ || ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST)
+#endif
+ ) {
+ currT = VAR_NUM(ZEND_OP1(opline).var);
+ if (!valid_T[currT]) {
+ GET_AVAILABLE_T();
+ map_T[currT] = i;
+ valid_T[currT] = 1;
+ }
+ ZEND_OP1(opline).var = NUM_VAR(map_T[currT]);
+ }
+
+ /* Skip OP_DATA */
+ if (opline->opcode == ZEND_OP_DATA &&
+ (opline-1)->opcode == ZEND_ASSIGN_DIM) {
+ opline--;
+ continue;
+ }
+
+ if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ || ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST)
+#endif
+ ) {
+ currT = VAR_NUM(ZEND_OP2(opline).var);
+ if (!valid_T[currT]) {
+ GET_AVAILABLE_T();
+ map_T[currT] = i;
+ valid_T[currT] = 1;
+ }
+ ZEND_OP2(opline).var = NUM_VAR(map_T[currT]);
+ }
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) {
+#else
+ if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
+ opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
+#endif
+ currT = VAR_NUM(opline->extended_value);
+ if (!valid_T[currT]) {
+ GET_AVAILABLE_T();
+ map_T[currT] = i;
+ valid_T[currT] = 1;
+ }
+ opline->extended_value = NUM_VAR(map_T[currT]);
+ }
+
+ /* Allocate OP_DATA->op2 after "operands", but before "result" */
+ if (opline->opcode == ZEND_ASSIGN_DIM &&
+ (opline + 1)->opcode == ZEND_OP_DATA &&
+ ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) {
+ currT = VAR_NUM(ZEND_OP2(opline + 1).var);
+ GET_AVAILABLE_T();
+ map_T[currT] = i;
+ valid_T[currT] = 1;
+ taken_T[i] = 0;
+ ZEND_OP2(opline + 1).var = NUM_VAR(i);
+ var_to_free = i;
+ }
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
+ if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
+#else
+ if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
+#endif
+ currT = VAR_NUM(ZEND_RESULT(opline).var);
+ if (valid_T[currT]) {
+ if (start_of_T[currT] == opline) {
+ taken_T[map_T[currT]] = 0;
+ }
+ ZEND_RESULT(opline).var = NUM_VAR(map_T[currT]);
+ } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
+ GET_AVAILABLE_T();
+
+ if (RESULT_UNUSED(opline)) {
+ taken_T[i] = 0;
+ } else {
+ /* Code which gets here is using a wrongly built opcode such as RECV() */
+ map_T[currT] = i;
+ valid_T[currT] = 1;
+ }
+ ZEND_RESULT(opline).var = NUM_VAR(i);
+ }
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ }
+#endif
+ }
+
+ if (var_to_free >= 0) {
+ taken_T[var_to_free] = 0;
+ var_to_free = -1;
+ }
+
+ opline--;
+ }
+
+ efree(taken_T);
+ efree(start_of_T);
+ efree(valid_T);
+ efree(map_T);
+ op_array->T = max + 1;
+}
diff --git a/ext/opcache/Optimizer/pass10.c b/ext/opcache/Optimizer/pass10.c
new file mode 100644
index 000000000..3bfcec643
--- /dev/null
+++ b/ext/opcache/Optimizer/pass10.c
@@ -0,0 +1,3 @@
+if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & OPTIMIZATION_LEVEL) == ZEND_OPTIMIZER_PASS_10) {
+ nop_removal(op_array);
+}
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
new file mode 100644
index 000000000..8938e148c
--- /dev/null
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -0,0 +1,391 @@
+/* pass 1
+ * - substitute persistent constants (true, false, null, etc)
+ * - perform compile-time evaluation of constant binary and unary operations
+ * - optimize series of ADD_STRING and/or ADD_CHAR
+ * - convert CAST(IS_BOOL,x) into BOOL(x)
+ * - convert INTI_FCALL_BY_NAME, DO_FCALL_BY_NAME into DO_FCALL
+ */
+
+if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
+ int i = 0;
+ zend_op *opline = op_array->opcodes;
+ zend_op *end = opline + op_array->last;
+
+ while (opline < end) {
+ switch (opline->opcode) {
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_DIV:
+ case ZEND_MOD:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_CONCAT:
+ 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_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ case ZEND_BOOL_XOR:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST &&
+ ZEND_OP2_TYPE(opline) == IS_CONST) {
+ /* binary operation with constant operands */
+ int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode);
+ zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */
+ zval result;
+ zend_op *tmp_opline;
+ int er;
+
+ if (opline->opcode == ZEND_DIV &&
+ Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG &&
+ Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) {
+ /* div by 0 */
+ break;
+ }
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ /* evaluate constant expression */
+ if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline) TSRMLS_CC) != SUCCESS) {
+ EG(error_reporting) = er;
+ break;
+ }
+ EG(error_reporting) = er;
+ PZ_SET_REFCOUNT_P(&result, 1);
+ PZ_UNSET_ISREF_P(&result);
+
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ MAKE_NOP(opline);
+
+ /* substitute the following TMP_VAR usage with constant */
+ for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
+ if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
+ ZEND_OP1(tmp_opline).var == tv) {
+ if (tmp_opline->opcode == ZEND_FREE) {
+ MAKE_NOP(tmp_opline);
+ zval_dtor(&result);
+ } else {
+ ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
+ if (Z_TYPE(result) == IS_STRING) {
+ Z_HASH_P(&ZEND_OP1_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP1_LITERAL(tmp_opline)) + 1);
+ if (tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
+ tmp_opline->opcode == ZEND_DO_FCALL ||
+ tmp_opline->opcode == ZEND_CATCH ||
+ tmp_opline->opcode == ZEND_FETCH_CONSTANT) {
+ op_array->literals[tmp_opline->op1.constant].cache_slot = op_array->last_cache_slot++;
+ }
+ }
+#else
+ ZEND_OP1_LITERAL(tmp_opline) = result;
+#endif
+ }
+ /* TMP_VAR my be used only once */
+ break;
+ }
+ if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
+ ZEND_OP2(tmp_opline).var == tv) {
+ ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
+ if (Z_TYPE(result) == IS_STRING) {
+ Z_HASH_P(&ZEND_OP2_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP2_LITERAL(tmp_opline)) + 1);
+ if (tmp_opline->opcode == ZEND_FETCH_R ||
+ tmp_opline->opcode == ZEND_FETCH_W ||
+ tmp_opline->opcode == ZEND_FETCH_RW ||
+ tmp_opline->opcode == ZEND_FETCH_IS ||
+ tmp_opline->opcode == ZEND_FETCH_UNSET ||
+ tmp_opline->opcode == ZEND_FETCH_FUNC_ARG ||
+ tmp_opline->opcode == ZEND_FETCH_CLASS ||
+ tmp_opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
+ tmp_opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
+ tmp_opline->opcode == ZEND_UNSET_VAR ||
+ tmp_opline->opcode == ZEND_ISSET_ISEMPTY_VAR ||
+ tmp_opline->opcode == ZEND_ADD_INTERFACE ||
+ tmp_opline->opcode == ZEND_ADD_TRAIT) {
+ op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot++;
+ } else if (tmp_opline->opcode == ZEND_INIT_METHOD_CALL ||
+ tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
+ tmp_opline->opcode == ZEND_FETCH_CONSTANT ||
+ tmp_opline->opcode == ZEND_ASSIGN_OBJ ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_R ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_W ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_RW ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_IS ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_UNSET ||
+ tmp_opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG ||
+ tmp_opline->opcode == ZEND_UNSET_OBJ ||
+ tmp_opline->opcode == ZEND_PRE_INC_OBJ ||
+ tmp_opline->opcode == ZEND_PRE_DEC_OBJ ||
+ tmp_opline->opcode == ZEND_POST_INC_OBJ ||
+ tmp_opline->opcode == ZEND_POST_DEC_OBJ ||
+ tmp_opline->opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ) {
+ op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
+ op_array->last_cache_slot += 2;
+ } else if (tmp_opline->opcode == ZEND_ASSIGN_ADD ||
+ tmp_opline->opcode == ZEND_ASSIGN_SUB ||
+ tmp_opline->opcode == ZEND_ASSIGN_MUL ||
+ tmp_opline->opcode == ZEND_ASSIGN_DIV ||
+ tmp_opline->opcode == ZEND_ASSIGN_MOD ||
+ tmp_opline->opcode == ZEND_ASSIGN_SL ||
+ tmp_opline->opcode == ZEND_ASSIGN_SR ||
+ tmp_opline->opcode == ZEND_ASSIGN_CONCAT ||
+ tmp_opline->opcode == ZEND_ASSIGN_BW_OR ||
+ tmp_opline->opcode == ZEND_ASSIGN_BW_AND ||
+ tmp_opline->opcode == ZEND_ASSIGN_BW_XOR) {
+ if (tmp_opline->extended_value == ZEND_ASSIGN_OBJ) {
+ op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
+ op_array->last_cache_slot += 2;
+ }
+ }
+ }
+#else
+ ZEND_OP2_LITERAL(tmp_opline) = result;
+#endif
+ break;
+ }
+ }
+ }
+ break;
+
+ case ZEND_CAST:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST &&
+ opline->extended_value != IS_ARRAY &&
+ opline->extended_value != IS_OBJECT &&
+ opline->extended_value != IS_RESOURCE) {
+ /* cast of constant operand */
+ zval res;
+ res = ZEND_OP1_LITERAL(opline);
+ zval_copy_ctor(&res);
+ switch (opline->extended_value) {
+ case IS_NULL:
+ convert_to_null(&res);
+ break;
+ case IS_BOOL:
+ convert_to_boolean(&res);
+ break;
+ case IS_LONG:
+ convert_to_long(&res);
+ break;
+ case IS_DOUBLE:
+ convert_to_double(&res);
+ break;
+ case IS_STRING:
+ convert_to_string(&res);
+ break;
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ ZEND_OP1_LITERAL(opline) = res;
+ SET_UNUSED(opline->op2);
+ } else if (opline->extended_value == IS_BOOL) {
+ /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
+ opline->opcode = ZEND_BOOL;
+ opline->extended_value = 0;
+ }
+ break;
+
+ case ZEND_BW_NOT:
+ case ZEND_BOOL_NOT:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ /* unary operation on constant operand */
+ unary_op_type unary_op = get_unary_op(opline->opcode);
+ zval result;
+ zend_op *tmp_opline;
+ zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */
+ int er;
+
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ if (unary_op(&result, &ZEND_OP1_LITERAL(opline) TSRMLS_CC) != SUCCESS) {
+ EG(error_reporting) = er;
+ break;
+ }
+ EG(error_reporting) = er;
+ PZ_SET_REFCOUNT_P(&result, 1);
+ PZ_UNSET_ISREF_P(&result);
+
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ MAKE_NOP(opline);
+
+ /* substitute the following TMP_VAR usage with constant */
+ for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
+ if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
+ ZEND_OP1(tmp_opline).var == tv) {
+ if (tmp_opline->opcode == ZEND_FREE) {
+ MAKE_NOP(tmp_opline);
+ zval_dtor(&result);
+ } else {
+ ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
+#else
+ ZEND_OP1_LITERAL(tmp_opline) = result;
+#endif
+ }
+ break;
+ }
+ if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
+ ZEND_OP2(tmp_opline).var == tv) {
+ ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
+#else
+ ZEND_OP2_LITERAL(tmp_opline) = result;
+#endif
+ break;
+ }
+ }
+ }
+ break;
+
+ case ZEND_ADD_STRING:
+ case ZEND_ADD_CHAR:
+ {
+ zend_op *next_op = opline + 1;
+ int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
+ size_t final_length = 0;
+ char *ptr;
+ zend_op *last_op;
+
+ /* There is always a ZEND_RETURN at the end
+ if (next_op>=end) {
+ break;
+ }
+ */
+ while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) {
+ if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) {
+ break;
+ }
+ if (next_op->opcode == ZEND_ADD_CHAR) {
+ final_length += 1;
+ } else { /* ZEND_ADD_STRING */
+ final_length += ZEND_OP2_LITERAL(next_op).value.str.len;
+ }
+ next_op++;
+ }
+ if (final_length == 0) {
+ break;
+ }
+ last_op = next_op;
+ final_length += (requires_conversion? 1 : ZEND_OP2_LITERAL(opline).value.str.len);
+ ptr = (char *)emalloc(final_length + 1);
+ ptr[final_length] = '\0';
+ if (requires_conversion) { /* ZEND_ADD_CHAR */
+ char chval = (char)ZEND_OP2_LITERAL(opline).value.lval;
+
+ ZEND_OP2_LITERAL(opline).value.str.val = ptr;
+ ptr[0] = chval;
+ ZEND_OP2_LITERAL(opline).type = IS_STRING;
+ opline->opcode = ZEND_ADD_STRING;
+ ptr++;
+ } else { /* ZEND_ADD_STRING */
+ memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
+ if (!IS_INTERNED(Z_STRVAL(ZEND_OP2_LITERAL(opline)))) {
+ efree(Z_STRVAL(ZEND_OP2_LITERAL(opline)));
+ }
+ Z_STRVAL(ZEND_OP2_LITERAL(opline)) = ptr;
+ ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
+ }
+ ZEND_OP2_LITERAL(opline).value.str.len = final_length;
+ next_op = opline + 1;
+ while (next_op < last_op) {
+ if (next_op->opcode == ZEND_ADD_STRING) {
+ memcpy(ptr, ZEND_OP2_LITERAL(next_op).value.str.val, ZEND_OP2_LITERAL(next_op).value.str.len);
+ ptr += ZEND_OP2_LITERAL(next_op).value.str.len;
+ literal_dtor(&ZEND_OP2_LITERAL(next_op));
+ } else { /* ZEND_ADD_CHAR */
+ *ptr = (char)ZEND_OP2_LITERAL(next_op).value.lval;
+ ptr++;
+ }
+ MAKE_NOP(next_op);
+ next_op++;
+ }
+ if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
+ /* NOP removal is disabled => insert JMP over NOPs */
+ if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
+ (opline + 1)->opcode = ZEND_JMP;
+ ZEND_OP1(opline + 1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */
+ }
+ }
+ }
+ break;
+
+ case ZEND_FETCH_CONSTANT:
+ if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
+ ZEND_OP2_TYPE(opline) == 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_bool orig_in_execution = EG(in_execution);
+ zend_op_array *orig_op_array = EG(active_op_array);
+ zval offset;
+
+ EG(in_execution) = 1;
+ EG(active_op_array) = op_array;
+ if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &offset TSRMLS_CC);
+#else
+ ZEND_OP1_LITERAL(opline) = offset;
+#endif
+ SET_UNUSED(opline->op2);
+ opline->opcode = ZEND_QM_ASSIGN;
+ }
+ EG(active_op_array) = orig_op_array;
+ EG(in_execution) = orig_in_execution;
+ break;
+ }
+
+ if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
+ ZEND_OP2_TYPE(opline) == IS_CONST &&
+ ZEND_OP2_LITERAL(opline).type == IS_STRING) {
+ /* substitute persistent constants */
+ zval c;
+
+ if (!zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) {
+ break;
+ }
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &c TSRMLS_CC);
+#else
+ ZEND_OP1_LITERAL(opline) = c;
+#endif
+ SET_UNUSED(opline->op2);
+ opline->opcode = ZEND_QM_ASSIGN;
+ }
+ break;
+
+ case ZEND_INIT_FCALL_BY_NAME:
+ if (opline->extended_value == 0 /* not method */ &&
+ ZEND_OP1_TYPE(opline) == IS_UNUSED &&
+ ZEND_OP2_TYPE(opline) == IS_CONST) {
+ if ((opline + 1)->opcode == ZEND_DO_FCALL_BY_NAME &&
+ (opline + 1)->extended_value == 0) {
+ (opline + 1)->opcode = ZEND_DO_FCALL;
+ COPY_NODE((opline + 1)->op1, opline->op2);
+ zend_str_tolower(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ Z_HASH_P(&ZEND_OP1_LITERAL(opline + 1)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)) + 1);
+ op_array->literals[(opline + 1)->op1.constant].cache_slot = op_array->last_cache_slot++;
+#endif
+ MAKE_NOP(opline);
+ }
+ }
+ break;
+ }
+ opline++;
+ i++;
+ }
+}
diff --git a/ext/opcache/Optimizer/pass2.c b/ext/opcache/Optimizer/pass2.c
new file mode 100644
index 000000000..30708a093
--- /dev/null
+++ b/ext/opcache/Optimizer/pass2.c
@@ -0,0 +1,211 @@
+/* pass 2:
+ * - convert non-numeric constants to numeric constants in numeric operators
+ * - optimize constant conditional JMPs
+ * - optimize static BRKs and CONTs
+ */
+
+if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
+ zend_op *opline;
+ zend_op *end = op_array->opcodes + op_array->last;
+
+ opline = op_array->opcodes;
+ while (opline < end) {
+ switch (opline->opcode) {
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_DIV:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP1_LITERAL(opline).type == IS_STRING) {
+ convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC);
+ }
+ }
+ /* break missing *intentionally* - the assign_op's may only optimize op2 */
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ if (opline->extended_value != 0) {
+ /* object tristate op - don't attempt to optimize it! */
+ break;
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP2_LITERAL(opline).type == IS_STRING) {
+ convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC);
+ }
+ }
+ break;
+
+ case ZEND_MOD:
+ case ZEND_SL:
+ case ZEND_SR:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP1_LITERAL(opline).type != IS_LONG) {
+ convert_to_long(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ /* break missing *intentionally - the assign_op's may only optimize op2 */
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ if (opline->extended_value != 0) {
+ /* object tristate op - don't attempt to optimize it! */
+ break;
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP2_LITERAL(opline).type != IS_LONG) {
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ break;
+
+ case ZEND_CONCAT:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP1_LITERAL(opline).type != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ /* break missing *intentionally - the assign_op's may only optimize op2 */
+ case ZEND_ASSIGN_CONCAT:
+ if (opline->extended_value != 0) {
+ /* object tristate op - don't attempt to optimize it! */
+ break;
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ if (ZEND_OP2_LITERAL(opline).type != IS_STRING) {
+ convert_to_string(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ break;
+
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
+ if (0 && /* FIXME: temporary disable unsafe pattern */
+ ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
+ ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
+ ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
+ opline->opcode -= 3;
+ /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
+ in case we know it wouldn't jump */
+ } else if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
+ if (opline->opcode == ZEND_JMPZ_EX) {
+ should_jmp = !should_jmp;
+ }
+ if (!should_jmp) {
+ opline->opcode = ZEND_QM_ASSIGN;
+ SET_UNUSED(opline->op2);
+ }
+ }
+ break;
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ if (ZEND_OP1_TYPE(opline) == 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));
+ ZEND_OP1_TYPE(opline) = IS_UNUSED;
+ if (should_jmp) {
+ opline->opcode = ZEND_JMP;
+ COPY_NODE(opline->op1, opline->op2);
+ } else {
+ MAKE_NOP(opline);
+ }
+ break;
+ }
+ if ((opline + 1)->opcode == ZEND_JMP) {
+ /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
+ /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
+ if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
+ /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
+ MAKE_NOP(opline);
+ } else {
+ if (opline->opcode == ZEND_JMPZ) {
+ opline->extended_value = ZEND_OP1(opline + 1).opline_num;
+ } else {
+ opline->extended_value = ZEND_OP2(opline).opline_num;
+ COPY_NODE(opline->op2, (opline + 1)->op1);
+ }
+ opline->opcode = ZEND_JMPZNZ;
+ }
+ }
+ break;
+
+ case ZEND_JMPZNZ:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ int opline_num;
+
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ opline_num = opline->extended_value; /* JMPNZ */
+ } else {
+ opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ ZEND_OP1(opline).opline_num = opline_num;
+ ZEND_OP1_TYPE(opline) = IS_UNUSED;
+ opline->opcode = ZEND_JMP;
+ }
+ break;
+
+ case ZEND_BRK:
+ case ZEND_CONT:
+ {
+ zend_brk_cont_element *jmp_to;
+ int array_offset;
+ int nest_levels;
+ int dont_optimize = 0;
+
+ if (ZEND_OP2_TYPE(opline) != IS_CONST) {
+ break;
+ }
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ nest_levels = ZEND_OP2_LITERAL(opline).value.lval;
+
+ array_offset = ZEND_OP1(opline).opline_num;
+ while (1) {
+ if (array_offset == -1) {
+ dont_optimize = 1; /* don't optimize this bogus break/continue, let the executor shout */
+ break;
+ }
+ jmp_to = &op_array->brk_cont_array[array_offset];
+ array_offset = jmp_to->parent;
+ if (--nest_levels > 0) {
+ if (opline->opcode == ZEND_BRK &&
+ (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
+ op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE)) {
+ dont_optimize = 1;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (dont_optimize) {
+ break;
+ }
+
+ /* optimize - convert to a JMP */
+ switch (opline->opcode) {
+ case ZEND_BRK:
+ MAKE_NOP(opline);
+ ZEND_OP1(opline).opline_num = jmp_to->brk;
+ break;
+ case ZEND_CONT:
+ MAKE_NOP(opline);
+ ZEND_OP1(opline).opline_num = jmp_to->cont;
+ break;
+ }
+ opline->opcode = ZEND_JMP;
+ /* MAKE_NOP() already set op1 and op2 to IS_UNUSED */
+ }
+ break;
+ }
+ opline++;
+ }
+}
diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c
new file mode 100644
index 000000000..fd2a19000
--- /dev/null
+++ b/ext/opcache/Optimizer/pass3.c
@@ -0,0 +1,442 @@
+/* pass 3:
+ * - optimize $i = $i+expr to $i+=expr
+ * - optimize series of JMPs
+ * - change $i++ to ++$i where possible
+ */
+
+/* compares opcodes with allowing oc1 be _EX of oc2 */
+#define SAME_OPCODE_EX(oc1, oc2) ((oc1 == oc2) || (oc1 == ZEND_JMPZ_EX && oc2 == ZEND_JMPZ) || (oc1 == ZEND_JMPNZ_EX && oc2 == ZEND_JMPNZ))
+
+/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
+#define CHECK_JMP(target, label) \
+ for (i=0; i<jmp_hitlist_count; i++) { \
+ if (jmp_hitlist[i] == ZEND_OP1(&op_array->opcodes[target]).opline_num) { \
+ goto label; \
+ } \
+ } \
+ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+
+#define CHECK_JMP2(target, label) \
+ for (i=0; i<jmp_hitlist_count; i++) { \
+ if (jmp_hitlist[i] == ZEND_OP2(&op_array->opcodes[target]).opline_num) { \
+ goto label; \
+ } \
+ } \
+ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+
+if (ZEND_OPTIMIZER_PASS_3 & OPTIMIZATION_LEVEL) {
+ zend_op *opline;
+ zend_op *end = op_array->opcodes + op_array->last;
+ zend_uint *jmp_hitlist;
+ int jmp_hitlist_count;
+ int i;
+ zend_uint opline_num = 0;
+ ALLOCA_FLAG(use_heap);
+
+ jmp_hitlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint)*op_array->last);
+ opline = op_array->opcodes;
+
+ while (opline < end) {
+ jmp_hitlist_count = 0;
+
+ switch (opline->opcode) {
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_DIV:
+ case ZEND_MOD:
+ case ZEND_CONCAT:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ {
+ zend_op *next_opline = opline + 1;
+
+ while (next_opline < end && next_opline->opcode == ZEND_NOP) {
+ ++next_opline;
+ }
+
+ if (next_opline >= end || next_opline->opcode != ZEND_ASSIGN) {
+ break;
+ }
+
+ if ((ZEND_OP2_TYPE(opline) == IS_VAR || ZEND_OP2_TYPE(opline) == IS_CV)
+ && ZEND_OP2(opline).var == ZEND_OP1(next_opline).var &&
+ (opline->opcode == ZEND_ADD ||
+ opline->opcode == ZEND_MUL ||
+ opline->opcode == ZEND_BW_OR ||
+ opline->opcode == ZEND_BW_AND ||
+ opline->opcode == ZEND_BW_XOR)) {
+ /* change $i=expr+$i to $i=$i+expr so that the next
+ * optimization works on it
+ */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ zend_uchar tmp_type = opline->op1_type;
+ znode_op tmp = opline->op1;
+#else
+ znode tmp = opline->op1;
+#endif
+
+ if (opline->opcode != ZEND_ADD || ZEND_OP1_TYPE(opline) == IS_CONST) {
+ /* protection from array add: $a = array + $a is not commutative! */
+ COPY_NODE(opline->op1, opline->op2);
+ COPY_NODE(opline->op2, tmp);
+ }
+ }
+ if ((ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_CV)
+ && ZEND_OP1(opline).var == ZEND_OP1(next_opline).var
+ && ZEND_OP1_TYPE(opline) == ZEND_OP1_TYPE(next_opline)) {
+ switch (opline->opcode) {
+ case ZEND_ADD:
+ opline->opcode = ZEND_ASSIGN_ADD;
+ break;
+ case ZEND_SUB:
+ opline->opcode = ZEND_ASSIGN_SUB;
+ break;
+ case ZEND_MUL:
+ opline->opcode = ZEND_ASSIGN_MUL;
+ break;
+ case ZEND_DIV:
+ opline->opcode = ZEND_ASSIGN_DIV;
+ break;
+ case ZEND_MOD:
+ opline->opcode = ZEND_ASSIGN_MOD;
+ break;
+ case ZEND_CONCAT:
+ opline->opcode = ZEND_ASSIGN_CONCAT;
+ break;
+ case ZEND_SL:
+ opline->opcode = ZEND_ASSIGN_SL;
+ break;
+ case ZEND_SR:
+ opline->opcode = ZEND_ASSIGN_SR;
+ break;
+ case ZEND_BW_OR:
+ opline->opcode = ZEND_ASSIGN_BW_OR;
+ break;
+ case ZEND_BW_AND:
+ opline->opcode = ZEND_ASSIGN_BW_AND;
+ break;
+ case ZEND_BW_XOR:
+ opline->opcode = ZEND_ASSIGN_BW_XOR;
+ break;
+ }
+ COPY_NODE(opline->result, next_opline->result);
+ MAKE_NOP(next_opline);
+ opline++;
+ opline_num++;
+ }
+ }
+ break;
+
+ case ZEND_JMP:
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ break;
+ }
+#endif
+
+ /* convert L: JMP L+1 to NOP */
+ if (ZEND_OP1(opline).opline_num == opline_num + 1) {
+ MAKE_NOP(opline);
+ goto done_jmp_optimization;
+ }
+
+ /* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
+ while (ZEND_OP1(opline).opline_num < op_array->last
+ && op_array->opcodes[ZEND_OP1(opline).opline_num].opcode == ZEND_JMP) {
+ int target = ZEND_OP1(opline).opline_num;
+ CHECK_JMP(target, done_jmp_optimization);
+ ZEND_OP1(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ }
+ break;
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_JMP_SET:
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ break;
+ }
+#endif
+
+ while (ZEND_OP2(opline).opline_num < op_array->last) {
+ int target = ZEND_OP2(opline).opline_num;
+ if (op_array->opcodes[target].opcode == ZEND_JMP) {
+ ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ } else {
+ break;
+ }
+ }
+ break;
+#endif
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ break;
+ }
+#endif
+
+ /* convert L: JMPZ L+1 to NOP */
+ if (ZEND_OP2(opline).opline_num == opline_num + 1) {
+ MAKE_NOP(opline);
+ goto done_jmp_optimization;
+ }
+
+ while (ZEND_OP2(opline).opline_num < op_array->last) {
+ int target = ZEND_OP2(opline).opline_num;
+
+ if (op_array->opcodes[target].opcode == ZEND_JMP) {
+ /* plain JMP */
+ /* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */
+ CHECK_JMP(target, done_jmp_optimization);
+ ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ } else if (op_array->opcodes[target].opcode == opline->opcode &&
+ SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ /* same opcode and same var as this opcode */
+ /* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */
+ CHECK_JMP2(target, done_jmp_optimization);
+ ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+ } else if (op_array->opcodes[target].opcode == opline->opcode + 3 &&
+ SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ /* convert JMPZ(X,L1), L1: T JMPZ_EX(X,L2) to
+ T = JMPZ_EX(X, L2) */
+ ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;opline->opcode += 3;
+ COPY_NODE(opline->result, op_array->opcodes[target].result);
+ break;
+ } else if (op_array->opcodes[target].opcode == INV_COND(opline->opcode) &&
+ SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ /* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to
+ JMPZ(X,L1+1) */
+ ZEND_OP2(opline).opline_num = target + 1;
+ break;
+ } else if (op_array->opcodes[target].opcode == INV_COND_EX(opline->opcode) &&
+ SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ /* convert JMPZ(X,L1), L1: T = JMPNZ_EX(X,L2) to
+ T = JMPZ_EX(X,L1+1) */
+ ZEND_OP2(opline).opline_num = target + 1;
+ opline->opcode += 3;
+ COPY_NODE(opline->result, op_array->opcodes[target].result);
+ break;
+ } else {
+ break;
+ }
+ }
+ break;
+
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX: {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ zend_uchar T_type = opline->result_type;
+ znode_op T = opline->result;
+#else
+ znode T = opline->result;
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ break;
+ }
+#endif
+ /* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
+ /* convert L: T = JMPZ_EX T,L+1 to NOP */
+ if (ZEND_OP2(opline).opline_num == opline_num + 1) {
+ if (ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
+ MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_BOOL;
+ SET_UNUSED(opline->op2);
+ }
+ goto done_jmp_optimization;
+ }
+
+ while (ZEND_OP2(opline).opline_num < op_array->last) {
+ int target = ZEND_OP2(opline).opline_num;
+ if (SAME_OPCODE_EX(opline->opcode, op_array->opcodes[target].opcode) &&
+ SAME_VAR(op_array->opcodes[target].op1, T)) {
+ /* Check for JMPZ_EX to JMPZ[_EX] with the same condition, either with _EX or not */
+ if (op_array->opcodes[target].opcode == opline->opcode) {
+ /* change T only if we have _EX opcode there */
+ COPY_NODE(T, op_array->opcodes[target].result);
+ }
+ CHECK_JMP2(target, continue_jmp_ex_optimization);
+ ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+ } else if (op_array->opcodes[target].opcode == ZEND_JMPZNZ &&
+ SAME_VAR(op_array->opcodes[target].op1, T)) {
+ /* Check for JMPZNZ with same cond variable */
+ int new_target;
+ CHECK_JMP2(target, continue_jmp_ex_optimization);
+ if (opline->opcode == ZEND_JMPZ_EX) {
+ new_target = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+ } else {
+ /* JMPNZ_EX */
+ new_target = op_array->opcodes[target].extended_value;
+ }
+ ZEND_OP2(opline).opline_num = new_target;
+ } else if ((op_array->opcodes[target].opcode == INV_EX_COND_EX(opline->opcode) ||
+ op_array->opcodes[target].opcode == INV_EX_COND(opline->opcode)) &&
+ SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ /* convert JMPZ_EX(X,L1), L1: JMPNZ_EX(X,L2) to
+ JMPZ_EX(X,L1+1) */
+ ZEND_OP2(opline).opline_num = target + 1;
+ break;
+ } else {
+ break;
+ }
+ } /* while */
+continue_jmp_ex_optimization:
+ break;
+#if 0
+ /* If Ti = JMPZ_EX(X, L) and Ti is not used, convert to JMPZ(X, L) */
+ {
+ zend_op *op;
+ for(op = opline+1; op<end; op++) {
+ if(ZEND_RESULT_TYPE(op) == IS_TMP_VAR &&
+ ZEND_RESULT(op).var == ZEND_RESULT(opline).var) {
+ break; /* can pass to part 2 */
+ }
+
+ if(op->opcode == ZEND_JMP ||
+ op->opcode == ZEND_JMPZ ||
+ op->opcode == ZEND_JMPZ_EX ||
+ op->opcode == ZEND_JMPNZ ||
+ op->opcode == ZEND_JMPNZ_EX ||
+ op->opcode == ZEND_JMPZNZ ||
+ op->opcode == ZEND_BRK ||
+ op->opcode == ZEND_CONT ||
+ op->opcode == ZEND_CASE ||
+ op->opcode == ZEND_RETURN ||
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ op->opcode == ZEND_RETURN_BY_REF ||
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ op->opcode == ZEND_FAST_RET ||
+#endif
+ op->opcode == ZEND_FE_FETCH ||
+ op->opcode == ZEND_EXIT) {
+ break;
+ }
+
+ if(ZEND_OP1_TYPE(op) == IS_TMP_VAR &&
+ ZEND_OP1(op).var == ZEND_RESULT(opline).var) {
+ goto done_jmp_optimization;
+ }
+
+ if(ZEND_OP2_TYPE(op) == IS_TMP_VAR &&
+ ZEND_OP2(op).var == ZEND_RESULT(opline).var) {
+ goto done_jmp_optimization;
+ }
+ } /* for */
+
+ for(op = &op_array->opcodes[ZEND_OP2(opline).opline_num]; op<end; op++) {
+
+ if(ZEND_RESULT_TYPE(op) == IS_TMP_VAR &&
+ ZEND_RESULT(op).var == ZEND_RESULT(opline).var) {
+ break; /* can pass to optimization */
+ }
+
+ if(op->opcode == ZEND_JMP ||
+ op->opcode == ZEND_JMPZ ||
+ op->opcode == ZEND_JMPZ_EX ||
+ op->opcode == ZEND_JMPNZ ||
+ op->opcode == ZEND_JMPNZ_EX ||
+ op->opcode == ZEND_JMPZNZ ||
+ op->opcode == ZEND_BRK ||
+ op->opcode == ZEND_CONT ||
+ op->opcode == ZEND_CASE ||
+ op->opcode == ZEND_RETURN ||
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ op->opcode == ZEND_RETURN_BY_REF ||
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ op->opcode == ZEND_FAST_RET ||
+#endif
+ op->opcode == ZEND_FE_FETCH ||
+ op->opcode == ZEND_EXIT) {
+ break;
+ }
+
+ if(ZEND_OP1_TYPE(op) == IS_TMP_VAR &&
+ ZEND_OP1(op).var == ZEND_RESULT(opline).var) {
+ goto done_jmp_optimization;
+ }
+
+ if(ZEND_OP2_TYPE(op) == IS_TMP_VAR &&
+ ZEND_OP2(op).var == ZEND_RESULT(opline).var) {
+ goto done_jmp_optimization;
+ }
+ }
+
+ opline->opcode = opline->opcode-3; /* JMP_EX -> JMP */
+ SET_UNUSED(opline->result);
+ break;
+ }
+#endif
+ }
+ break;
+
+ case ZEND_JMPZNZ:
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ if (op_array->has_finally_block) {
+ break;
+ }
+#endif
+ /* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
+ while (ZEND_OP2(opline).opline_num < op_array->last
+ && op_array->opcodes[ZEND_OP2(opline).opline_num].opcode == ZEND_JMP) {
+ int target = ZEND_OP2(opline).opline_num;
+ CHECK_JMP(target, continue_jmpznz_optimization);
+ ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ }
+continue_jmpznz_optimization:
+ /* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
+ while (opline->extended_value < op_array->last
+ && op_array->opcodes[opline->extended_value].opcode == ZEND_JMP) {
+ int target = opline->extended_value;
+ CHECK_JMP(target, done_jmp_optimization);
+ opline->extended_value = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ }
+ break;
+
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC: {
+ /* POST_INC, FREE => PRE_INC */
+ zend_op *next_op = opline + 1;
+
+ if (next_op >= end) {
+ break;
+ }
+ if (next_op->opcode == ZEND_FREE &&
+ ZEND_OP1(next_op).var == ZEND_RESULT(opline).var) {
+ MAKE_NOP(next_op);
+ switch (opline->opcode) {
+ case ZEND_POST_INC:
+ opline->opcode = ZEND_PRE_INC;
+ break;
+ case ZEND_POST_DEC:
+ opline->opcode = ZEND_PRE_DEC;
+ break;
+ }
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ZEND_RESULT_TYPE(opline) = IS_VAR | EXT_TYPE_UNUSED;
+#else
+ ZEND_RESULT_TYPE(opline) = IS_VAR;
+ ZEND_RESULT(opline).EA.type = 0;
+ ZEND_RESULT(opline).EA.type |= EXT_TYPE_UNUSED;
+#endif
+ }
+ }
+ break;
+ }
+done_jmp_optimization:
+ opline++;
+ opline_num++;
+ }
+ FREE_ALLOCA(jmp_hitlist);
+}
diff --git a/ext/opcache/Optimizer/pass5.c b/ext/opcache/Optimizer/pass5.c
new file mode 100644
index 000000000..b0d651a5f
--- /dev/null
+++ b/ext/opcache/Optimizer/pass5.c
@@ -0,0 +1,3 @@
+if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) {
+ zend_block_optimization(op_array TSRMLS_CC);
+}
diff --git a/ext/opcache/Optimizer/pass9.c b/ext/opcache/Optimizer/pass9.c
new file mode 100644
index 000000000..586160c14
--- /dev/null
+++ b/ext/opcache/Optimizer/pass9.c
@@ -0,0 +1,8 @@
+/* pass 9
+ *
+ * - optimize usage of temporary variables
+ */
+
+if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) {
+ optimize_temporary_variables(op_array);
+}
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
new file mode 100644
index 000000000..b574ecc81
--- /dev/null
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -0,0 +1,139 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "Optimizer/zend_optimizer.h"
+#include "Optimizer/zend_optimizer_internal.h"
+#include "zend_API.h"
+#include "zend_constants.h"
+#include "zend_execute.h"
+
+#define OPTIMIZATION_LEVEL \
+ ZCG(accel_directives).optimization_level
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC)
+{
+ int i = op_array->last_literal;
+ op_array->last_literal++;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ {
+ if (i >= CG(context).literals_size) {
+ CG(context).literals_size += 16; /* FIXME */
+ op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));
+ }
+ }
+#else
+ if (i >= op_array->size_literal) {
+ op_array->size_literal += 16; /* FIXME */
+ op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->size_literal * sizeof(zend_literal));
+ }
+#endif
+ op_array->literals[i].constant = *zv;
+ Z_SET_REFCOUNT(op_array->literals[i].constant, 2);
+ Z_SET_ISREF(op_array->literals[i].constant);
+ return i;
+}
+
+# define LITERAL_LONG(op, val) do { \
+ zval _c; \
+ ZVAL_LONG(&_c, val); \
+ op.constant = zend_optimizer_add_literal(op_array, &_c TSRMLS_CC); \
+ } while (0)
+
+# define LITERAL_BOOL(op, val) do { \
+ zval _c; \
+ ZVAL_BOOL(&_c, val); \
+ op.constant = zend_optimizer_add_literal(op_array, &_c TSRMLS_CC); \
+ } while (0)
+
+# define literal_dtor(zv) do { \
+ zval_dtor(zv); \
+ Z_TYPE_P(zv) = IS_NULL; \
+ } while (0)
+
+#define COPY_NODE(target, src) do { \
+ target ## _type = src ## _type; \
+ target = src; \
+ } while (0)
+
+#else
+
+# define LITERAL_LONG(op, val) ZVAL_LONG(&op.u.constant, val)
+
+# define LITERAL_BOOL(op, val) ZVAL_BOOL(&op.u.constant, val)
+
+# define literal_dtor(zv) zval_dtor(zv)
+
+#define COPY_NODE(target, src) do { \
+ target = src; \
+ } while (0)
+
+#endif
+
+#include "Optimizer/nop_removal.c"
+#include "Optimizer/block_pass.c"
+#include "Optimizer/optimize_temp_vars_5.c"
+
+void zend_optimizer(zend_op_array *op_array TSRMLS_DC)
+{
+ if (op_array->type == ZEND_EVAL_CODE ||
+ (op_array->fn_flags & ZEND_ACC_INTERACTIVE)) {
+ return;
+ }
+
+ /* pass 1
+ * - substitute persistent constants (true, false, null, etc)
+ * - perform compile-time evaluation of constant binary and unary operations
+ * - optimize series of ADD_STRING and/or ADD_CHAR
+ * - convert CAST(IS_BOOL,x) into BOOL(x)
+ * - convert INTI_FCALL_BY_NAME + DO_FCALL_BY_NAME into DO_FCALL
+ */
+#include "Optimizer/pass1_5.c"
+
+ /* pass 2:
+ * - convert non-numeric constants to numeric constants in numeric operators
+ * - optimize constant conditional JMPs
+ * - optimize static BRKs and CONTs
+ */
+#include "Optimizer/pass2.c"
+
+ /* pass 3:
+ * - optimize $i = $i+expr to $i+=expr
+ * - optimize series of JMPs
+ * - change $i++ to ++$i where possible
+ */
+#include "Optimizer/pass3.c"
+
+ /* pass 5:
+ * - CFG optimization
+ */
+#include "Optimizer/pass5.c"
+
+ /* pass 9:
+ * - Optimize temp variables usage
+ */
+#include "Optimizer/pass9.c"
+
+ /* pass 10:
+ * - remove NOPs
+ */
+#include "Optimizer/pass10.c"
+}
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h
new file mode 100644
index 000000000..98275a20a
--- /dev/null
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_OPTIMIZER_H
+#define ZEND_OPTIMIZER_H
+
+#include "zend.h"
+#include "zend_compile.h"
+
+#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */
+#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jumps */
+#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */
+#define ZEND_OPTIMIZER_PASS_4 (1<<3)
+#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
+#define ZEND_OPTIMIZER_PASS_6 (1<<5)
+#define ZEND_OPTIMIZER_PASS_7 (1<<6)
+#define ZEND_OPTIMIZER_PASS_8 (1<<7)
+#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)
+#define ZEND_OPTIMIZER_PASS_12 (1<<11)
+#define ZEND_OPTIMIZER_PASS_13 (1<<12)
+#define ZEND_OPTIMIZER_PASS_14 (1<<13)
+
+#define ZEND_OPTIMIZER_ALL_PASSES 0xFFFFFFFF
+
+#define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFFFFF"
+
+void zend_optimizer(zend_op_array *op_array TSRMLS_DC);
+
+#endif
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
new file mode 100644
index 000000000..0097496df
--- /dev/null
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -0,0 +1,83 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_OPTIMIZER_INTERNAL_H
+#define ZEND_OPTIMIZER_INTERNAL_H
+
+#include "ZendAccelerator.h"
+
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+# define VAR_NUM(v) ((zend_uint)(EX_TMP_VAR_NUM(0, 0) - EX_TMP_VAR(0, v)))
+# define NUM_VAR(v) ((zend_uint)EX_TMP_VAR_NUM(0, v))
+#else
+# define VAR_NUM(v) ((v)/(sizeof(temp_variable)))
+# define NUM_VAR(v) ((v)*(sizeof(temp_variable)))
+#endif
+
+#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)
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; }
+# define RESULT_USED(op) (((op->result_type & IS_VAR) && !(op->result_type & EXT_TYPE_UNUSED)) || op->result_type == IS_TMP_VAR)
+# define RESULT_UNUSED(op) ((op->result_type & EXT_TYPE_UNUSED) != 0)
+# define SAME_VAR(op1, op2) ((((op1 ## _type & IS_VAR) && (op2 ## _type & IS_VAR)) || (op1 ## _type == IS_TMP_VAR && op2 ## _type == IS_TMP_VAR)) && op1.var == op2.var)
+#else
+# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(znode)); memset(&opline->op1,0,sizeof(znode)); memset(&opline->op2,0,sizeof(znode)); opline->result.op_type=opline->op1.op_type=opline->op2.op_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; }
+# define RESULT_USED(op) ((op->result.op_type == IS_VAR && (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) || (op->result.op_type == IS_TMP_VAR))
+# define RESULT_UNUSED(op) ((op->result.op_type == IS_VAR) && (op->result.u.EA.type == EXT_TYPE_UNUSED))
+# define SAME_VAR(op1, op2) (((op1.op_type == IS_VAR && op2.op_type == IS_VAR) || (op1.op_type == IS_TMP_VAR && op2.op_type == IS_TMP_VAR)) && op1.u.var == op2.u.var)
+#endif
+
+typedef struct _zend_code_block zend_code_block;
+typedef struct _zend_block_source zend_block_source;
+
+struct _zend_code_block {
+ int access;
+ zend_op *start_opline;
+ int start_opline_no;
+ int len;
+ zend_code_block *op1_to;
+ zend_code_block *op2_to;
+ zend_code_block *ext_to;
+ zend_code_block *follow_to;
+ zend_code_block *next;
+ zend_block_source *sources;
+ zend_bool protected; /* don't merge this block with others */
+};
+
+typedef struct _zend_cfg {
+ zend_code_block *blocks;
+ zend_code_block **try;
+ zend_code_block **catch;
+ zend_code_block **loop_start;
+ zend_code_block **loop_cont;
+ zend_code_block **loop_brk;
+} zend_cfg;
+
+struct _zend_block_source {
+ zend_code_block *from;
+ zend_block_source *next;
+};
+
+#endif
diff --git a/ext/opcache/README b/ext/opcache/README
new file mode 100644
index 000000000..f87e1ccbf
--- /dev/null
+++ b/ext/opcache/README
@@ -0,0 +1,202 @@
+The Zend OPcache
+================
+
+The Zend OPcache provides faster PHP execution through opcode caching and
+optimization. It improves PHP performance by storing precompiled script
+bytecode in the shared memory. This eliminates the stages of reading code from
+the disk and compiling it on future access. In addition, it applies a few
+bytecode optimization patterns that make code execution faster.
+
+Compatibility
+-------------
+
+This version of Zend OPcache is compatible with PHP 5.2.*, 5.3.*, 5.4.*
+and PHP-5.5 development branch. PHP 5.2 support may be removed in the future.
+
+Quick Install
+-------------
+
+- Compile
+
+ $PHP_DIR/bin/phpize
+ ./configure \
+ --with-php-config=$PHP_DIR/bin/php-config
+ make
+
+- Install
+
+ make install # this will copy opcache.so into PHP extension directory
+
+- Edit php.ini
+
+ zend_extension=/...full path.../opcache.so
+
+NOTE: In case you are going to use Zend OPcache together with Xdebug,
+be sure that Xdebug is loaded after OPcache. "php -v" must show Xdebug
+after OPcache.
+
+- Restart PHP
+
+Speed Tuning
+-------------
+
+We recommend the following configuration options for best performance.
+
+opcache.memory_consumption=128
+opcache.interned_strings_buffer=8
+opcache.max_accelerated_files=4000
+opcache.revalidate_freq=60
+opcache.fast_shutdown=1
+opcache.enable_cli=1
+
+You also may add the following, but it may break some applications and
+frameworks. Please, read description of these directives and add them on your
+own risk.
+
+opcache.save_comments=0
+opcache.enable_file_override=1
+
+In some cases you may like to prefer enabling/disabling some features
+to avoid incompatibilities at the cost of some performance degradation.
+
+Configuration Directives
+------------------------
+
+opcache.enable (default "1")
+ OPcache On/Off switch. When set to Off, code is not optimized.
+
+opcache.memory_consumption (default "64")
+ The OPcache shared memory storage size. The amount of memory for storing
+ precompiled PHP code in Mbytes.
+
+opcache.interned_strings_buffer (default "4")
+ The amount of memory for interned strings in Mbytes.
+
+opcache.max_accelerated_files (default "2000")
+ The maximum number of keys (scripts) in the OPcache hash table.
+ The number is actually the first one in the following set of prime
+ numbers that is bigger than the one supplied: { 223, 463, 983, 1979, 3907,
+ 7963, 16229, 32531, 65407, 130987 }. Only numbers between 200 and 100000
+ are allowed.
+
+opcache.max_wasted_percentage (default "5")
+ The maximum percentage of "wasted" memory until a restart is scheduled.
+
+opcache.use_cwd (default "1")
+ When this directive is enabled, the OPcache appends the current working
+ directory to the script key, thus eliminating possible collisions between
+ files with the same name (basename). Disabling the directive improves
+ performance, but may break existing applications.
+
+opcache.validate_timestamps (default "1")
+ When disabled, you must reset the OPcache manually or restart the
+ webserver for changes to the filesystem to take effect.
+ The frequency of the check is controlled by the directive
+ "opcache.revalidate_freq".
+
+opcache.revalidate_freq (default "2")
+ How often (in seconds) to check file timestamps for changes to the shared
+ memory storage allocation. ("1" means validate once per second, but only
+ once per request. "0" means always validate)
+
+opcache.revalidate_path (default "0")
+ Enables or disables file search in include_path optimization
+ If the file search is disabled and a cached file is found that uses
+ the same include_path, the file is not searched again. Thus, if a file
+ with the same name appears somewhere else in include_path, it
+ won't be found. Enable this directive if this optimization has an effect on
+ your applications. The default for this directive is disabled, which means
+ that optimization is active.
+
+opcache.save_comments (default "1")
+ If disabled, all PHPDoc comments are dropped from the code to reduce the
+ size of the optimized code. Disabling "Doc Comments" may break some
+ existing applications and frameworks (e.g. Doctrine, ZF2, PHPUnit)
+
+opcache.load_comments (default "1")
+ If disabled, PHPDoc comments are not loaded from SHM, so "Doc Comments"
+ may be always stored (save_comments=1), but not loaded by applications
+ that don't need them anyway.
+
+opcache.fast_shutdown (default "0")
+ If enabled, a fast shutdown sequence is used for the accelerated code
+ The fast shutdown sequence doesn't free each allocated block, but lets
+ the Zend Engine Memory Manager do the work.
+
+opcache.enable_file_override (default "0")
+ Allow file existence override (file_exists, etc.) performance feature.
+
+opcache.optimization_level (default "0xffffffff")
+ A bitmask, where each bit enables or disables the appropriate OPcache
+ passes
+
+opcache.inherited_hack (default "1")
+ Enable this hack as a workaround for "can't redeclare class" errors.
+ The OPcache stores the places where DECLARE_CLASS opcodes use
+ inheritance (These are the only opcodes that can be executed by PHP,
+ but which may not be executed because the parent class is missing due to
+ optimization). When the file is loaded, OPcache tries to bind the
+ inherited classes by using the current environment. The problem with this
+ scenario is that, while the DECLARE_CLASS opcode may not be needed for the
+ current script, if the script requires that the opcode at least be defined,
+ it may not run. The default for this directive is disabled, which means
+ that optimization is active. In php-5.3 and above this hack is not needed
+ anymore and this setting has no effect.
+
+opcache.dups_fix (default "0")
+ Enable this hack as a workaround for "Cannot redeclare class" errors.
+
+opcache.blacklist_filename
+ The location of the OPcache blacklist file.
+ The OPcache blacklist file is a text file that holds the names of files
+ that should not be accelerated. The file format is to add each filename
+ to a new line. The filename may be a full path or just a file prefix
+ (i.e., /var/www/x blacklists all the files and directories in /var/www
+ that start with 'x'). Files are usually triggered by one of the following
+ three reasons:
+ 1) Directories that contain auto generated code, like Smarty or ZFW cache.
+ 2) Code that does not work well when accelerated, due to some delayed
+ compile time evaluation.
+ 3) Code that triggers an OPcache bug.
+
+opcache.max_file_size (default "0")
+ Allows exclusion of large files from being cached. By default all files
+ are cached.
+
+opcache.consistency_checks (default "0")
+ Check the cache checksum each N requests.
+ The default value of "0" means that the checks are disabled.
+ Because calculating the checksum impairs performance, this directive should
+ be enabled only as part of a debugging process.
+
+opcache.force_restart_timeout (default "180")
+ How long to wait (in seconds) for a scheduled restart to begin if the cache
+ is not being accessed.
+ The OPcache uses this directive to identify a situation where there may
+ be a problem with a process. After this time period has passed, the
+ OPcache assumes that something has happened and starts killing the
+ processes that still hold the locks that are preventing a restart.
+ If the log level is 3 or above, a "killed locker" error is recorded
+ in the Apache logs when this happens.
+
+opcache.error_log
+ OPcache error_log file name. Empty string assumes "stderr".
+
+opcache.log_verbosity_level (default "1")
+ All OPcache errors go to the Web server log.
+ By default, only fatal errors (level 0) or errors (level 1) are logged.
+ You can also enable warnings (level 2), info messages (level 3) or
+ debug messages (level 4).
+
+opcache.preferred_memory_model
+ Preferred Shared Memory back-end. Leave empty and let the system decide.
+
+opcache.protect_memory (default "0")
+ Protect the shared memory from unexpected writing during script execution.
+ Useful for internal debugging only.
+
+opcache.mmap_base
+ Mapping base of shared memory segments (for Windows only). All the PHP
+ processes have to map shared memory into the same address space. This
+ directive allows to manually fix the "Unable to reattach to base address"
+ errors.
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
new file mode 100644
index 000000000..64c5aa8f1
--- /dev/null
+++ b/ext/opcache/ZendAccelerator.c
@@ -0,0 +1,2656 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "main/php.h"
+#include "main/php_globals.h"
+#include "zend.h"
+#include "zend_extensions.h"
+#include "zend_compile.h"
+#include "ZendAccelerator.h"
+#include "zend_persist.h"
+#include "zend_shared_alloc.h"
+#include "zend_accelerator_module.h"
+#include "zend_accelerator_blacklist.h"
+#include "zend_list.h"
+#include "zend_execute.h"
+#include "main/SAPI.h"
+#include "main/php_streams.h"
+#include "main/php_open_temporary_file.h"
+#include "zend_API.h"
+#include "zend_ini.h"
+#include "TSRM/tsrm_virtual_cwd.h"
+#include "zend_accelerator_util_funcs.h"
+#include "zend_accelerator_hash.h"
+
+#ifndef ZEND_WIN32
+#include <netdb.h>
+#endif
+
+#ifdef ZEND_WIN32
+typedef int uid_t;
+typedef int gid_t;
+#include <io.h>
+#endif
+
+#ifndef ZEND_WIN32
+# include <sys/time.h>
+#else
+# include <process.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+
+#ifndef ZEND_WIN32
+# include <sys/types.h>
+# include <sys/ipc.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+#define SHM_PROTECT() \
+ do { \
+ if (ZCG(accel_directives).protect_memory) { \
+ zend_accel_shared_protect(1 TSRMLS_CC); \
+ } \
+ } while (0)
+#define SHM_UNPROTECT() \
+ do { \
+ if (ZCG(accel_directives).protect_memory) { \
+ zend_accel_shared_protect(0 TSRMLS_CC); \
+ } \
+ } while (0)
+
+ZEND_EXTENSION();
+
+#ifndef ZTS
+zend_accel_globals accel_globals;
+#else
+int accel_globals_id;
+#endif
+
+/* Points to the structure shared across all PHP processes */
+zend_accel_shared_globals *accel_shared_globals = NULL;
+
+/* true globals, no need for thread safety */
+zend_bool accel_startup_ok = 0;
+static char *zps_failure_reason = NULL;
+char *zps_api_failure_reason = NULL;
+
+static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
+static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+static char *(*accelerator_orig_zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
+#endif
+static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
+static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
+
+#ifdef ZEND_WIN32
+# define INCREMENT(v) InterlockedIncrement(&ZCSG(v))
+# define DECREMENT(v) InterlockedDecrement(&ZCSG(v))
+# define LOCKVAL(v) (ZCSG(v))
+#endif
+
+#ifdef ZEND_WIN32
+static time_t zend_accel_get_time(void)
+{
+ FILETIME now;
+ GetSystemTimeAsFileTime(&now);
+
+ return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
+}
+#else
+# define zend_accel_get_time() time(NULL)
+#endif
+
+static inline int is_stream_path(const char *filename)
+{
+ const char *p;
+
+ for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ return ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/'));
+}
+
+/* O+ overrides PHP chdir() function and remembers the current working directory
+ * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
+ * avoid getcwd() call.
+ */
+static ZEND_FUNCTION(accel_chdir)
+{
+ char cwd[MAXPATHLEN];
+
+ orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
+ if (ZCG(cwd)) {
+ efree(ZCG(cwd));
+ }
+ ZCG(cwd_len) = strlen(cwd);
+ ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
+ } else {
+ if (ZCG(cwd)) {
+ efree(ZCG(cwd));
+ ZCG(cwd) = NULL;
+ }
+ }
+}
+
+static inline char* accel_getcwd(int *cwd_len TSRMLS_DC)
+{
+ if (ZCG(cwd)) {
+ *cwd_len = ZCG(cwd_len);
+ return ZCG(cwd);
+ } else {
+ char cwd[MAXPATHLEN + 1];
+
+ if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
+ return NULL;
+ }
+ *cwd_len = ZCG(cwd_len) = strlen(cwd);
+ ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
+ return ZCG(cwd);
+ }
+}
+
+/* O+ tracks changes of "include_path" directive. It stores all the requested
+ * values in ZCG(include_paths) shared hash table, current value in
+ * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
+ * ZCG(include_path_key).
+ */
+static ZEND_INI_MH(accel_include_path_on_modify)
+{
+ int ret = orig_include_path_on_modify(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+
+ ZCG(include_path_key) = NULL;
+ if (ret == SUCCESS) {
+ ZCG(include_path) = new_value;
+ if (ZCG(include_path) && *ZCG(include_path)) {
+ ZCG(include_path_len) = new_value_length;
+
+ if (ZCG(enabled) && accel_startup_ok &&
+ (ZCG(counted) || ZCSG(accelerator_enabled)) &&
+ !zend_accel_hash_is_full(&ZCSG(include_paths))) {
+
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock(TSRMLS_C);
+
+ ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
+ if (!ZCG(include_path_key) &&
+ !zend_accel_hash_is_full(&ZCSG(include_paths))) {
+ char *key;
+
+ key = zend_shared_alloc(ZCG(include_path_len) + 2);
+ if (key) {
+ memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
+ key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
+ ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
+ zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
+ }
+ }
+
+ zend_shared_alloc_unlock(TSRMLS_C);
+ SHM_PROTECT();
+ } else {
+ ZCG(include_path_check) = 1;
+ }
+ } else {
+ ZCG(include_path) = "";
+ ZCG(include_path_len) = 0;
+ }
+ }
+ return ret;
+}
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+/* Interned strings support */
+static char *orig_interned_strings_start;
+static char *orig_interned_strings_end;
+static const char *(*orig_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
+static void (*orig_interned_strings_snapshot)(TSRMLS_D);
+static void (*orig_interned_strings_restore)(TSRMLS_D);
+
+/* O+ disables creation of interned strings by regular PHP compiler, instead,
+ * it creates interned strings in shared memory when saves a script.
+ * Such interned strings are shared across all PHP processes
+ */
+static const char *accel_new_interned_string_for_php(const char *str, int len, int free_src TSRMLS_DC)
+{
+ return str;
+}
+
+static void accel_interned_strings_snapshot_for_php(TSRMLS_D)
+{
+}
+
+static void accel_interned_strings_restore_for_php(TSRMLS_D)
+{
+}
+
+#ifndef ZTS
+static void accel_interned_strings_restore_state(TSRMLS_D)
+{
+ unsigned int i;
+
+ for (i = 0; i < ZCSG(interned_strings).nTableSize; i++) {
+ ZCSG(interned_strings).arBuckets[i] = ZCSG(interned_strings_saved_state).arBuckets[i];
+ if (ZCSG(interned_strings).arBuckets[i]) {
+ ZCSG(interned_strings).arBuckets[i]->pLast = NULL;
+ }
+ }
+ ZCSG(interned_strings).pListHead = ZCSG(interned_strings_saved_state).pListHead;
+ ZCSG(interned_strings).pListTail = ZCSG(interned_strings_saved_state).pListTail;
+ if (ZCSG(interned_strings).pListHead) {
+ ZCSG(interned_strings).pListHead->pListLast = NULL;
+ }
+ if (ZCSG(interned_strings).pListTail) {
+ ZCSG(interned_strings).pListTail->pListNext = NULL;
+ }
+ ZCSG(interned_strings_top) = ZCSG(interned_strings_saved_state).top;
+}
+
+static void accel_interned_strings_save_state(TSRMLS_D)
+{
+ ZCSG(interned_strings_saved_state).arBuckets = (Bucket**)zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
+ if (!ZCSG(interned_strings_saved_state).arBuckets) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ }
+ memcpy(ZCSG(interned_strings_saved_state).arBuckets, ZCSG(interned_strings).arBuckets, ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
+ ZCSG(interned_strings_saved_state).pListHead = ZCSG(interned_strings).pListHead;
+ ZCSG(interned_strings_saved_state).pListTail = ZCSG(interned_strings).pListTail;
+ ZCSG(interned_strings_saved_state).top = ZCSG(interned_strings_top);
+}
+#endif
+
+const char *accel_new_interned_string(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
+{
+/* for now interned strings are supported only for non-ZTS build */
+#ifndef ZTS
+ ulong h;
+ uint nIndex;
+ Bucket *p;
+
+ if (arKey >= ZCSG(interned_strings_start) && arKey < ZCSG(interned_strings_end)) {
+ /* this is already an interned string */
+ return arKey;
+ }
+
+ h = zend_inline_hash_func(arKey, nKeyLength);
+ nIndex = h & ZCSG(interned_strings).nTableMask;
+
+ /* check for existing interned string */
+ p = ZCSG(interned_strings).arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == (uint)nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ if (free_src) {
+ efree((char*)arKey);
+ }
+ return p->arKey;
+ }
+ }
+ p = p->pNext;
+ }
+
+ if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
+ ZCSG(interned_strings_end)) {
+ /* no memory, return the same non-interned string */
+ return arKey;
+ }
+
+ /* create new interning string in shared interned strings buffer */
+ p = (Bucket *) ZCSG(interned_strings_top);
+ ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
+
+ p->arKey = (char*)(p + 1);
+ memcpy((char*)p->arKey, arKey, nKeyLength);
+ p->nKeyLength = nKeyLength;
+ p->h = h;
+ p->pData = &p->pDataPtr;
+ p->pDataPtr = p;
+
+ p->pNext = ZCSG(interned_strings).arBuckets[nIndex];
+ p->pLast = NULL;
+ if (p->pNext) {
+ p->pNext->pLast = p;
+ }
+ ZCSG(interned_strings).arBuckets[nIndex] = p;
+
+ p->pListLast = ZCSG(interned_strings).pListTail;
+ ZCSG(interned_strings).pListTail = p;
+ p->pListNext = NULL;
+ if (p->pListLast != NULL) {
+ p->pListLast->pListNext = p;
+ }
+ if (!ZCSG(interned_strings).pListHead) {
+ ZCSG(interned_strings).pListHead = p;
+ }
+
+ ZCSG(interned_strings).nNumOfElements++;
+
+ if (free_src) {
+ efree((char*)arKey);
+ }
+
+ return p->arKey;
+#else
+ return arKey;
+#endif
+}
+
+#ifndef ZTS
+/* Copy PHP interned strings from PHP process memory into the shared memory */
+static void accel_use_shm_interned_strings(TSRMLS_D)
+{
+ Bucket *p, *q;
+
+ /* function table hash keys */
+ p = CG(function_table)->pListHead;
+ while (p) {
+ if (p->nKeyLength) {
+ p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
+ }
+ p = p->pListNext;
+ }
+
+ /* class table hash keys, class names, properties, methods, constants, etc */
+ p = CG(class_table)->pListHead;
+ while (p) {
+ zend_class_entry *ce = (zend_class_entry*)(p->pDataPtr);
+
+ if (p->nKeyLength) {
+ p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
+ }
+
+ if (ce->name) {
+ ce->name = accel_new_interned_string(ce->name, ce->name_length + 1, 0 TSRMLS_CC);
+ }
+
+ q = ce->properties_info.pListHead;
+ while (q) {
+ zend_property_info *info = (zend_property_info*)(q->pData);
+
+ if (q->nKeyLength) {
+ q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
+ }
+
+ if (info->name) {
+ info->name = accel_new_interned_string(info->name, info->name_length + 1, 0 TSRMLS_CC);
+ }
+
+ q = q->pListNext;
+ }
+
+ q = ce->function_table.pListHead;
+ while (q) {
+ if (q->nKeyLength) {
+ q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
+ }
+ q = q->pListNext;
+ }
+
+ q = ce->constants_table.pListHead;
+ while (q) {
+ if (q->nKeyLength) {
+ q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
+ }
+ q = q->pListNext;
+ }
+
+ p = p->pListNext;
+ }
+
+ /* constant hash keys */
+ p = EG(zend_constants)->pListHead;
+ while (p) {
+ if (p->nKeyLength) {
+ p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
+ }
+ p = p->pListNext;
+ }
+
+ /* auto globals hash keys and names */
+ p = CG(auto_globals)->pListHead;
+ while (p) {
+ zend_auto_global *auto_global = (zend_auto_global*)p->pData;
+
+ auto_global->name = accel_new_interned_string(auto_global->name, auto_global->name_len + 1, 0 TSRMLS_CC);
+ if (p->nKeyLength) {
+ p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
+ }
+ p = p->pListNext;
+ }
+}
+#endif
+#endif
+
+static inline void accel_restart_enter(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ INCREMENT(restart_in);
+#else
+ static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
+
+ if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno);
+ }
+#endif
+ ZCSG(restart_in_progress) = 1;
+}
+
+static inline void accel_restart_leave(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ ZCSG(restart_in_progress) = 0;
+ DECREMENT(restart_in);
+#else
+ static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
+
+ ZCSG(restart_in_progress) = 0;
+ if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno);
+ }
+#endif
+}
+
+static inline int accel_restart_is_active(TSRMLS_D)
+{
+ if (ZCSG(restart_in_progress)) {
+#ifndef ZEND_WIN32
+ FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1);
+
+ if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno);
+ return FAILURE;
+ }
+ if (restart_check.l_type == F_UNLCK) {
+ ZCSG(restart_in_progress) = 0;
+ return 0;
+ } else {
+ return 1;
+ }
+#else
+ return LOCKVAL(restart_in) != 0;
+#endif
+ }
+ return 0;
+}
+
+/* Creates a read lock for SHM access */
+static inline void accel_activate_add(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ INCREMENT(mem_usage);
+#else
+ static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
+
+ if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno);
+ }
+#endif
+}
+
+/* Releases a lock for SHM access */
+static inline void accel_deactivate_sub(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ if (ZCG(counted)) {
+ DECREMENT(mem_usage);
+ ZCG(counted) = 0;
+ }
+#else
+ static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
+
+ if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno);
+ }
+#endif
+}
+
+static inline void accel_unlock_all(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ accel_deactivate_sub(TSRMLS_C);
+#else
+ static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
+
+ if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno);
+ }
+#endif
+}
+
+#ifndef ZEND_WIN32
+static inline void kill_all_lockers(struct flock *mem_usage_check)
+{
+ int tries = 10;
+
+ /* so that other process won't try to force while we are busy cleaning up */
+ ZCSG(force_restart_time) = 0;
+ while (mem_usage_check->l_pid > 0) {
+ while (tries--) {
+ zend_accel_error(ACCEL_LOG_INFO, "Killed locker %d", mem_usage_check->l_pid);
+ if (kill(mem_usage_check->l_pid, SIGKILL)) {
+ break;
+ }
+ /* give it a chance to die */
+ usleep(20000);
+ if (kill(mem_usage_check->l_pid, 0)) {
+ /* can't kill it */
+ break;
+ }
+ usleep(10000);
+ }
+ if (!tries) {
+ zend_accel_error(ACCEL_LOG_INFO, "Can't kill %d after 20 tries!", mem_usage_check->l_pid);
+ ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
+ }
+
+ mem_usage_check->l_type = F_WRLCK;
+ mem_usage_check->l_whence = SEEK_SET;
+ mem_usage_check->l_start = 1;
+ mem_usage_check->l_len = 1;
+ mem_usage_check->l_pid = -1;
+ if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "KLockers: %s (%d)", strerror(errno), errno);
+ break;
+ }
+
+ if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
+ break;
+ }
+ }
+}
+#endif
+
+static inline int accel_is_inactive(TSRMLS_D)
+{
+#ifdef ZEND_WIN32
+ if (LOCKVAL(mem_usage) == 0) {
+ return SUCCESS;
+ }
+#else
+ FLOCK_STRUCTURE(mem_usage_check, F_WRLCK, SEEK_SET, 1, 1);
+
+ mem_usage_check.l_pid = -1;
+ if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC: %s (%d)", strerror(errno), errno);
+ return FAILURE;
+ }
+ if (mem_usage_check.l_type == F_UNLCK) {
+ return SUCCESS;
+ }
+
+ if (ZCG(accel_directives).force_restart_timeout
+ && ZCSG(force_restart_time)
+ && time(NULL) >= ZCSG(force_restart_time)) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %d (after %d seconds), locked by %d", time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
+ kill_all_lockers(&mem_usage_check);
+
+ return FAILURE; /* next request should be able to restart it */
+ }
+#endif
+
+ return FAILURE;
+}
+
+static int zend_get_stream_timestamp(const char *filename, struct stat *statbuf TSRMLS_DC)
+{
+ php_stream_wrapper *wrapper;
+ php_stream_statbuf stream_statbuf;
+ int ret, er;
+
+ if (!filename) {
+ return FAILURE;
+ }
+
+ wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC);
+ if (!wrapper) {
+ return FAILURE;
+ }
+ if (!wrapper->wops || !wrapper->wops->url_stat) {
+ statbuf->st_mtime = 1;
+ return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
+ }
+
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ zend_try {
+ ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL TSRMLS_CC);
+ } zend_catch {
+ ret = -1;
+ } zend_end_try();
+ EG(error_reporting) = er;
+
+ if (ret != 0) {
+ return FAILURE;
+ }
+
+ *statbuf = stream_statbuf.sb;
+ return SUCCESS;
+}
+
+#if ZEND_WIN32
+static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
+{
+ static unsigned __int64 utc_base = 0;
+ static FILETIME utc_base_ft;
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+
+ if (!file_handle->opened_path) {
+ return 0;
+ }
+
+ if (!utc_base) {
+ SYSTEMTIME st;
+
+ st.wYear = 1970;
+ st.wMonth = 1;
+ st.wDay = 1;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+
+ SystemTimeToFileTime (&st, &utc_base_ft);
+ utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
+ }
+
+ if (GetFileAttributesEx(file_handle->opened_path, GetFileExInfoStandard, &fdata) != 0) {
+ unsigned __int64 ftime;
+
+ if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
+ return 0;
+ }
+
+ ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
+ ftime /= 10000000L;
+
+ if (size) {
+ *size = (size_t)(((unsigned __int64)fdata.nFileSizeHigh) << 32 + (unsigned __int64)fdata.nFileSizeLow);
+ }
+ return (accel_time_t)ftime;
+ }
+ return 0;
+}
+#endif
+
+static accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size TSRMLS_DC)
+{
+ struct stat statbuf;
+#ifdef ZEND_WIN32
+ accel_time_t res;
+#endif
+
+ if (sapi_module.get_stat &&
+ !EG(opline_ptr) &&
+ file_handle->filename == SG(request_info).path_translated) {
+
+ struct stat *tmpbuf = sapi_module.get_stat(TSRMLS_C);
+
+ if (tmpbuf) {
+ if (size) {
+ *size = tmpbuf->st_size;
+ }
+ return tmpbuf->st_mtime;
+ }
+ }
+
+#ifdef ZEND_WIN32
+ res = zend_get_file_handle_timestamp_win(file_handle, size);
+ if (res) {
+ return res;
+ }
+#endif
+
+ switch (file_handle->type) {
+ case ZEND_HANDLE_FD:
+ if (fstat(file_handle->handle.fd, &statbuf) == -1) {
+ return 0;
+ }
+ break;
+ case ZEND_HANDLE_FP:
+ if (fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
+ if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
+ return 0;
+ }
+ }
+ break;
+ case ZEND_HANDLE_FILENAME:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ case ZEND_HANDLE_MAPPED:
+#endif
+ {
+ char *file_path = file_handle->opened_path;
+
+ if (file_path) {
+ if (is_stream_path(file_path)) {
+ if (zend_get_stream_timestamp(file_path, &statbuf TSRMLS_CC) == SUCCESS) {
+ break;
+ }
+ }
+ if (VCWD_STAT(file_path, &statbuf) != -1) {
+ break;
+ }
+ }
+
+ if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
+ return 0;
+ }
+ break;
+ }
+ case ZEND_HANDLE_STREAM:
+ {
+ php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
+ php_stream_statbuf sb;
+ int ret, er;
+
+ if (!stream ||
+ !stream->ops ||
+ !stream->ops->stat) {
+ return 0;
+ }
+
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ zend_try {
+ ret = stream->ops->stat(stream, &sb TSRMLS_CC);
+ } zend_catch {
+ ret = -1;
+ } zend_end_try();
+ EG(error_reporting) = er;
+ if (ret != 0) {
+ return 0;
+ }
+
+ statbuf = sb.sb;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (size) {
+ *size = statbuf.st_size;
+ }
+ return statbuf.st_mtime;
+}
+
+static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
+{
+ zend_file_handle ps_handle;
+ char actualpath [MAXPATHLEN + 1];
+ char *full_path_ptr = NULL;
+
+ /** check that the persistant script is indeed the same file we cached
+ * (if part of the path is a symlink than it possible that the user will change it)
+ * See bug #15140
+ */
+ if (file_handle->opened_path) {
+ if (strcmp(persistent_script->full_path, file_handle->opened_path) != 0) {
+ return FAILURE;
+ }
+ } else {
+ full_path_ptr = VCWD_REALPATH(file_handle->filename, actualpath);
+ if (full_path_ptr && strcmp(persistent_script->full_path, full_path_ptr) != 0) {
+ return FAILURE;
+ }
+ file_handle->opened_path = full_path_ptr;
+ }
+
+ if (persistent_script->timestamp == 0) {
+ if (full_path_ptr) {
+ file_handle->opened_path = NULL;
+ }
+ return FAILURE;
+ }
+
+ if (zend_get_file_handle_timestamp(file_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
+ if (full_path_ptr) {
+ file_handle->opened_path = NULL;
+ }
+ return SUCCESS;
+ }
+ if (full_path_ptr) {
+ file_handle->opened_path = NULL;
+ }
+
+ ps_handle.type = ZEND_HANDLE_FILENAME;
+ ps_handle.filename = persistent_script->full_path;
+ ps_handle.opened_path = persistent_script->full_path;
+
+ if (zend_get_file_handle_timestamp(&ps_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
+ return SUCCESS;
+ }
+
+ return FAILURE;
+}
+
+static void zend_accel_schedule_restart_if_necessary(TSRMLS_D)
+{
+ if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
+ ZSMMG(memory_exhausted) = 1;
+ zend_accel_schedule_restart(ACCEL_RESTART_WASTED TSRMLS_CC);
+ }
+}
+
+static inline int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
+{
+ if (ZCG(accel_directives).revalidate_freq &&
+ (persistent_script->dynamic_members.revalidate >= ZCSG(revalidate_at))) {
+ return SUCCESS;
+ } else if (do_validate_timestamps(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ } else {
+ persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
+ return SUCCESS;
+ }
+}
+
+static unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
+{
+ signed char *mem = (signed char*)persistent_script->mem;
+ size_t size = persistent_script->size;
+ size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
+ unsigned int checksum = ADLER32_INIT;
+
+ if (mem < (signed char*)persistent_script) {
+ checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
+ size -= (signed char*)persistent_script - mem;
+ mem += (signed char*)persistent_script - mem;
+ }
+
+ zend_adler32(checksum, mem, persistent_script_check_block_size);
+ mem += sizeof(*persistent_script);
+ size -= sizeof(*persistent_script);
+
+ if (size > 0) {
+ checksum = zend_adler32(checksum, mem, size);
+ }
+ return checksum;
+}
+
+/* Instead of resolving full real path name each time we need to identify file,
+ * we create a key that consist from requested file name, current working
+ * directory, current include_path, etc */
+char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC)
+{
+ int key_length;
+
+ /* CWD and include_path don't matter for absolute file names and streams */
+ if (ZCG(accel_directives).use_cwd &&
+ !IS_ABSOLUTE_PATH(file_handle->filename, path_length) &&
+ !is_stream_path(file_handle->filename)) {
+ char *include_path = NULL;
+ int include_path_len = 0;
+ const char *parent_script = NULL;
+ int parent_script_len = 0;
+ int cur_len = 0;
+ int cwd_len;
+ char *cwd;
+
+ if ((cwd = accel_getcwd(&cwd_len TSRMLS_CC)) == NULL) {
+ /* we don't handle this well for now. */
+ zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", file_handle->filename, errno);
+ if (file_handle->opened_path) {
+ cwd = file_handle->opened_path;
+ cwd_len = strlen(cwd);
+ } else {
+ ZCG(key_len) = 0;
+ return NULL;
+ }
+ }
+
+ if (ZCG(include_path_key)) {
+ include_path = ZCG(include_path_key);
+ include_path_len = 1;
+ } else {
+ include_path = ZCG(include_path);
+ include_path_len = ZCG(include_path_len);
+ if (ZCG(include_path_check) &&
+ ZCG(enabled) && accel_startup_ok &&
+ (ZCG(counted) || ZCSG(accelerator_enabled)) &&
+ !zend_accel_hash_is_full(&ZCSG(include_paths))) {
+
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock(TSRMLS_C);
+
+ ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
+ if (ZCG(include_path_key)) {
+ include_path = ZCG(include_path_key);
+ include_path_len = 1;
+ } else if (!zend_accel_hash_is_full(&ZCSG(include_paths))) {
+ char *key;
+
+ key = zend_shared_alloc(ZCG(include_path_len) + 2);
+ if (key) {
+ memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
+ key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
+ ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
+ zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
+ include_path = ZCG(include_path_key);
+ include_path_len = 1;
+ }
+ }
+
+ zend_shared_alloc_unlock(TSRMLS_C);
+ SHM_PROTECT();
+ }
+ }
+
+ /* Here we add to the key the parent script directory,
+ since fopen_wrappers from version 4.0.7 use current script's path
+ in include path too.
+ */
+ if (EG(in_execution) &&
+ (parent_script = zend_get_executed_filename(TSRMLS_C)) != NULL &&
+ parent_script[0] != '[') {
+
+ parent_script_len = strlen(parent_script);
+ while ((--parent_script_len > 0) && !IS_SLASH(parent_script[parent_script_len]));
+ }
+
+ /* Calculate key length */
+ key_length = cwd_len + path_length + include_path_len + 2;
+ if (parent_script_len) {
+ key_length += parent_script_len + 1;
+ }
+
+ /* Generate key
+ * Note - the include_path must be the last element in the key,
+ * since in itself, it may include colons (which we use to separate
+ * different components of the key)
+ */
+ if ((size_t)key_length >= sizeof(ZCG(key))) {
+ ZCG(key_len) = 0;
+ return NULL;
+ }
+ memcpy(ZCG(key), cwd, cwd_len);
+ ZCG(key)[cwd_len] = ':';
+
+ memcpy(ZCG(key) + cwd_len + 1, file_handle->filename, path_length);
+
+ ZCG(key)[cwd_len + 1 + path_length] = ':';
+
+ cur_len = cwd_len + 1 + path_length + 1;
+
+ if (parent_script_len) {
+ memcpy(ZCG(key) + cur_len, parent_script, parent_script_len);
+ cur_len += parent_script_len;
+ ZCG(key)[cur_len] = ':';
+ cur_len++;
+ }
+ memcpy(ZCG(key) + cur_len, include_path, include_path_len);
+ ZCG(key)[key_length] = '\0';
+ } else {
+ /* not use_cwd */
+ key_length = path_length;
+ if ((size_t)key_length >= sizeof(ZCG(key))) {
+ ZCG(key_len) = 0;
+ return NULL;
+ }
+ memcpy(ZCG(key), file_handle->filename, key_length + 1);
+ }
+
+ *key_len = ZCG(key_len) = key_length;
+ return ZCG(key);
+}
+
+static inline char *accel_make_persistent_key(zend_file_handle *file_handle, int *key_len TSRMLS_DC)
+{
+ return accel_make_persistent_key_ex(file_handle, strlen(file_handle->filename), key_len TSRMLS_CC);
+}
+
+/* Adds another key for existing cached script */
+static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket TSRMLS_DC)
+{
+ if (!zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) {
+ if (zend_accel_hash_is_full(&ZCSG(hash))) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
+ ZSMMG(memory_exhausted) = 1;
+ zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC);
+ } else {
+ char *new_key = zend_shared_alloc(key_length + 1);
+ if (new_key) {
+ memcpy(new_key, key, key_length + 1);
+ zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket);
+ }
+ }
+ }
+}
+
+static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory TSRMLS_DC)
+{
+ zend_accel_hash_entry *bucket;
+ uint memory_used;
+
+ /* Check if script may be stored in shared memory */
+ if (!zend_accel_script_persistable(new_persistent_script)) {
+ return new_persistent_script;
+ }
+
+ /* exclusive lock */
+ zend_shared_alloc_lock(TSRMLS_C);
+
+ if (zend_accel_hash_is_full(&ZCSG(hash))) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
+ ZSMMG(memory_exhausted) = 1;
+ zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC);
+ zend_shared_alloc_unlock(TSRMLS_C);
+ return new_persistent_script;
+ }
+
+ /* Check if we still need to put the file into the cache (may be it was
+ * already stored by another process. This final check is done under
+ * exclusive lock) */
+ bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1);
+ if (bucket) {
+ zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
+
+ if (!existing_persistent_script->corrupted) {
+ if (!ZCG(accel_directives).validate_timestamps ||
+ (new_persistent_script->timestamp == existing_persistent_script->timestamp)) {
+ zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
+ }
+ zend_shared_alloc_unlock(TSRMLS_C);
+ return new_persistent_script;
+ }
+ }
+
+ /* Calculate the required memory size */
+ memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length TSRMLS_CC);
+
+ /* Allocate shared memory */
+ ZCG(mem) = zend_shared_alloc(memory_used);
+ if (!ZCG(mem)) {
+ zend_shared_alloc_unlock(TSRMLS_C);
+ return new_persistent_script;
+ }
+
+ /* cleanup after calculation */
+ new_persistent_script->mem = ZCG(mem);
+ new_persistent_script->size = memory_used;
+
+ /* Copy into shared memory */
+ new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length TSRMLS_CC);
+
+ /* Consistency check */
+ if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
+ zend_accel_error(
+ ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
+ "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
+ new_persistent_script->full_path,
+ new_persistent_script->mem,
+ (char *)new_persistent_script->mem + new_persistent_script->size,
+ ZCG(mem));
+ }
+
+ new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
+
+ /* store script structure in the hash table */
+ bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1, 0, new_persistent_script);
+ if (bucket &&
+ (new_persistent_script->full_path_len != key_length ||
+ memcmp(new_persistent_script->full_path, key, key_length) != 0)) {
+ /* link key to the same persistent script in hash table */
+ if (!zend_accel_hash_update(&ZCSG(hash), key, key_length + 1, 1, bucket)) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
+ ZSMMG(memory_exhausted) = 1;
+ zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC);
+ }
+ }
+
+ new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
+
+ zend_shared_alloc_unlock(TSRMLS_C);
+
+ *from_shared_memory = 1;
+ return new_persistent_script;
+}
+
+static const struct jit_auto_global_info
+{
+ const char *name;
+ size_t len;
+} jit_auto_globals_info[] = {
+ { "_SERVER", sizeof("_SERVER")},
+ { "_ENV", sizeof("_ENV")},
+ { "_REQUEST", sizeof("_REQUEST")},
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ { "GLOBALS", sizeof("GLOBALS")},
+#endif
+};
+
+static int zend_accel_get_auto_globals(TSRMLS_D)
+{
+ int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
+ int n = 1;
+ int mask = 0;
+
+ for (i = 0; i < ag_size ; i++) {
+ if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_info[i].name, jit_auto_globals_info[i].len)) {
+ mask |= n;
+ }
+ n += n;
+ }
+ return mask;
+}
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+static int zend_accel_get_auto_globals_no_jit(TSRMLS_D)
+{
+ if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_info[3].name, jit_auto_globals_info[3].len)) {
+ return 8;
+ }
+ return 0;
+}
+#endif
+
+static void zend_accel_set_auto_globals(int mask TSRMLS_DC)
+{
+ int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
+ int n = 1;
+
+ for (i = 0; i < ag_size ; i++) {
+ if (mask & n) {
+ zend_is_auto_global(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len - 1 TSRMLS_CC);
+ }
+ n += n;
+ }
+}
+
+static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p, int *from_shared_memory TSRMLS_DC)
+{
+ zend_persistent_script *new_persistent_script;
+ zend_op_array *orig_active_op_array;
+ HashTable *orig_function_table, *orig_class_table;
+ zval *orig_user_error_handler;
+ zend_op_array *op_array;
+ int do_bailout = 0;
+ accel_time_t timestamp = 0;
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ zend_uint orig_compiler_options = 0;
+#endif
+
+ /* Try to open file */
+ if (file_handle->type == ZEND_HANDLE_FILENAME) {
+ if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == SUCCESS) {
+ /* key may be changed by zend_stream_open_function() */
+ if (key == ZCG(key)) {
+ key_length = ZCG(key_len);
+ }
+ } else {
+ *op_array_p = NULL;
+ if (type == ZEND_REQUIRE) {
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
+ zend_bailout();
+ } else {
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
+ }
+ return NULL;
+ }
+ }
+
+ /* check blacklist right after ensuring that file was opened */
+ if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, file_handle->opened_path)) {
+ ZCSG(blacklist_misses)++;
+ *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ return NULL;
+ }
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if (file_handle->type == ZEND_HANDLE_STREAM &&
+ (!strstr(file_handle->filename, ".phar") ||
+ strstr(file_handle->filename, "://"))) {
+ char *buf;
+ size_t size;
+
+ /* Stream callbacks needs to be called in context of original
+ * function and class tables (see: https://bugs.php.net/bug.php?id=64353)
+ */
+ if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == FAILURE) {
+ *op_array_p = NULL;
+ return NULL;
+ }
+ }
+#endif
+
+ if (ZCG(accel_directives).validate_timestamps || ZCG(accel_directives).max_file_size > 0) {
+ size_t size = 0;
+
+ /* Obtain the file timestamps, *before* actually compiling them,
+ * otherwise we have a race-condition.
+ */
+ timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL TSRMLS_CC);
+
+ /* If we can't obtain a timestamp (that means file is possibly socket)
+ * we won't cache it
+ */
+ if (timestamp == 0) {
+ *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ return NULL;
+ }
+
+ if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
+ ZCSG(blacklist_misses)++;
+ *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ return NULL;
+ }
+ }
+
+ new_persistent_script = create_persistent_script();
+
+ /* Save the original values for the op_array, function table and class table */
+ orig_active_op_array = CG(active_op_array);
+ orig_function_table = CG(function_table);
+ orig_class_table = CG(class_table);
+ orig_user_error_handler = EG(user_error_handler);
+
+ /* Override them with ours */
+ CG(function_table) = &ZCG(function_table);
+ EG(class_table) = CG(class_table) = &new_persistent_script->class_table;
+ EG(user_error_handler) = NULL;
+
+ zend_try {
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ orig_compiler_options = CG(compiler_options);
+ CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
+ CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
+ CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
+ CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
+#endif
+ op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ CG(compiler_options) = orig_compiler_options;
+#endif
+ } zend_catch {
+ op_array = NULL;
+ do_bailout = 1;
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ CG(compiler_options) = orig_compiler_options;
+#endif
+ } zend_end_try();
+
+ /* Restore originals */
+ CG(active_op_array) = orig_active_op_array;
+ CG(function_table) = orig_function_table;
+ EG(class_table) = CG(class_table) = orig_class_table;
+ EG(user_error_handler) = orig_user_error_handler;
+
+ if (!op_array) {
+ /* compilation failed */
+ free_persistent_script(new_persistent_script, 1);
+ zend_accel_free_user_functions(&ZCG(function_table) TSRMLS_CC);
+ if (do_bailout) {
+ zend_bailout();
+ }
+ return NULL;
+ }
+
+ /* Build the persistent_script structure.
+ Here we aren't sure we would store it, but we will need it
+ further anyway.
+ */
+ zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->function_table TSRMLS_CC);
+ new_persistent_script->main_op_array = *op_array;
+
+ efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
+
+ /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
+ will have to ping the used auto global variables before execution */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (PG(auto_globals_jit)) {
+ new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals(TSRMLS_C);
+ } else {
+ new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit(TSRMLS_C);
+ }
+#else
+ if ((PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays))) {
+ new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals(TSRMLS_C);
+ }
+#endif
+
+ if (ZCG(accel_directives).validate_timestamps) {
+ /* Obtain the file timestamps, *before* actually compiling them,
+ * otherwise we have a race-condition.
+ */
+ new_persistent_script->timestamp = timestamp;
+ new_persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
+ }
+
+ if (file_handle->opened_path) {
+ new_persistent_script->full_path_len = strlen(file_handle->opened_path);
+ new_persistent_script->full_path = estrndup(file_handle->opened_path, new_persistent_script->full_path_len);
+ } else {
+ new_persistent_script->full_path_len = strlen(file_handle->filename);
+ new_persistent_script->full_path = estrndup(file_handle->filename, new_persistent_script->full_path_len);
+ }
+ new_persistent_script->hash_value = zend_hash_func(new_persistent_script->full_path, new_persistent_script->full_path_len + 1);
+
+ /* Now persistent_script structure is ready in process memory */
+ return cache_script_in_shared_memory(new_persistent_script, key, key_length, from_shared_memory TSRMLS_CC);
+}
+
+/* zend_compile() replacement */
+static zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
+{
+ zend_persistent_script *persistent_script = NULL;
+ char *key = NULL;
+ int key_length;
+ int from_shared_memory; /* if the script we've got is stored in SHM */
+
+ if (!file_handle->filename ||
+ !ZCG(enabled) || !accel_startup_ok ||
+ (!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
+ CG(interactive) ||
+ (ZCSG(restart_in_progress) && accel_restart_is_active(TSRMLS_C))) {
+ /* The Accelerator is disabled, act as if without the Accelerator */
+ return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ }
+
+ /* Make sure we only increase the currently running processes semaphore
+ * once each execution (this function can be called more than once on
+ * each execution)
+ */
+ if (!ZCG(counted)) {
+ ZCG(counted) = 1;
+ accel_activate_add(TSRMLS_C);
+ }
+
+ /* In case this callback is called from include_once, require_once or it's
+ * a main FastCGI request, the key must be already calculated, and cached
+ * persistent script already found */
+ if ((EG(opline_ptr) == NULL &&
+ ZCG(cache_opline) == NULL &&
+ file_handle->filename == SG(request_info).path_translated &&
+ ZCG(cache_persistent_script)) ||
+ (EG(opline_ptr) && *EG(opline_ptr) &&
+ *EG(opline_ptr) == ZCG(cache_opline) &&
+ (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
+#else
+ ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
+#endif
+ if (!ZCG(key_len)) {
+ return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ }
+ /* persistent script was already found by overridden open() or
+ * resolve_path() callbacks */
+ persistent_script = ZCG(cache_persistent_script);
+ key = ZCG(key);
+ key_length = ZCG(key_len);
+ } else {
+ /* try to find cached script by key */
+ if ((key = accel_make_persistent_key(file_handle, &key_length TSRMLS_CC)) == NULL) {
+ return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ }
+ persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1);
+ if (!persistent_script) {
+ /* try to find cached script by full real path */
+ zend_accel_hash_entry *bucket;
+
+ /* open file to resolve the path */
+ if (file_handle->type == ZEND_HANDLE_FILENAME &&
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
+#else
+ zend_stream_open(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
+#endif
+ if (type == ZEND_REQUIRE) {
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
+ zend_bailout();
+ } else {
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
+ }
+ return NULL;
+ }
+
+ if (file_handle->opened_path &&
+ (bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path, strlen(file_handle->opened_path) + 1)) != NULL) {
+
+ persistent_script = (zend_persistent_script *)bucket->data;
+ if (!ZCG(accel_directives).revalidate_path &&
+ !persistent_script->corrupted) {
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock(TSRMLS_C);
+ zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
+ zend_shared_alloc_unlock(TSRMLS_C);
+ SHM_PROTECT();
+ }
+ }
+ }
+ }
+
+ /* clear cache */
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+
+ if (persistent_script && persistent_script->corrupted) {
+ persistent_script = NULL;
+ }
+
+ SHM_UNPROTECT();
+
+ /* If script is found then validate_timestamps if option is enabled */
+ if (persistent_script && ZCG(accel_directives).validate_timestamps) {
+ if (validate_timestamp_and_record(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
+ zend_shared_alloc_lock(TSRMLS_C);
+ if (!persistent_script->corrupted) {
+ persistent_script->corrupted = 1;
+ persistent_script->timestamp = 0;
+ ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
+ zend_accel_schedule_restart_if_necessary(TSRMLS_C);
+ }
+ zend_shared_alloc_unlock(TSRMLS_C);
+ persistent_script = NULL;
+ }
+ }
+
+ /* if turned on - check the compiled script ADLER32 checksum */
+ if (persistent_script && ZCG(accel_directives).consistency_checks
+ && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
+
+ unsigned int checksum = zend_accel_script_checksum(persistent_script);
+ if (checksum != persistent_script->dynamic_members.checksum ) {
+ /* The checksum is wrong */
+ zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s': expected=0x%0.8X, found=0x%0.8X",
+ persistent_script->full_path, persistent_script->dynamic_members.checksum, checksum);
+ zend_shared_alloc_lock(TSRMLS_C);
+ if (!persistent_script->corrupted) {
+ persistent_script->corrupted = 1;
+ persistent_script->timestamp = 0;
+ ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
+ zend_accel_schedule_restart_if_necessary(TSRMLS_C);
+ }
+ zend_shared_alloc_unlock(TSRMLS_C);
+ persistent_script = NULL;
+ }
+ }
+
+ /* If script was not found or invalidated by validate_timestamps */
+ if (!persistent_script) {
+ zend_op_array *op_array;
+
+ /* Cache miss.. */
+ ZCSG(misses)++;
+
+ /* No memory left. Behave like without the Accelerator */
+ if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
+ SHM_PROTECT();
+ return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
+ }
+
+ /* Try and cache the script and assume that it is returned from_shared_memory.
+ * If it isn't compile_and_cache_file() changes the flag to 0
+ */
+ from_shared_memory = 0;
+ persistent_script = compile_and_cache_file(file_handle, type, key, key_length, &op_array, &from_shared_memory TSRMLS_CC);
+
+ /* Something went wrong during compilation, returning NULL */
+ if (!persistent_script) {
+ SHM_PROTECT();
+ return op_array; /* Presently always NULL, but not necessary in the future */
+ }
+ } else {
+
+#if !ZEND_WIN32
+ ZCSG(hits)++; /* TBFixed: may lose one hit */
+ persistent_script->dynamic_members.hits++; /* see above */
+#else
+ InterlockedIncrement(&ZCSG(hits));
+ InterlockedIncrement(&persistent_script->dynamic_members.hits);
+#endif
+
+ /* see bug #15471 (old BTS) */
+ if (persistent_script->full_path) {
+ if (!EG(opline_ptr) || !*EG(opline_ptr) ||
+ (*EG(opline_ptr))->opcode != ZEND_INCLUDE_OR_EVAL ||
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ((*EG(opline_ptr))->extended_value != ZEND_INCLUDE_ONCE &&
+ (*EG(opline_ptr))->extended_value != ZEND_REQUIRE_ONCE)) {
+#else
+ ((*EG(opline_ptr))->op2.u.constant.value.lval != ZEND_INCLUDE_ONCE &&
+ (*EG(opline_ptr))->op2.u.constant.value.lval != ZEND_REQUIRE_ONCE)) {
+#endif
+ void *dummy = (void *) 1;
+
+ zend_hash_quick_add(&EG(included_files), persistent_script->full_path, persistent_script->full_path_len + 1, persistent_script->hash_value, &dummy, sizeof(void *), NULL);
+ }
+ }
+ zend_file_handle_dtor(file_handle TSRMLS_CC);
+ from_shared_memory = 1;
+ }
+
+ persistent_script->dynamic_members.last_used = ZCG(request_time);
+
+ SHM_PROTECT();
+
+ /* Fetch jit auto globals used in the script before execution */
+ if (persistent_script->ping_auto_globals_mask) {
+ zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask TSRMLS_CC);
+ }
+
+ return zend_accel_load_script(persistent_script, from_shared_memory TSRMLS_CC);
+}
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+
+/* Taken from php-5.2.5 because early versions don't have correct version */
+static char *accel_tsrm_realpath(const char *path, int path_len TSRMLS_DC)
+{
+ cwd_state new_state;
+ char *real_path;
+ char *cwd;
+ int cwd_len;
+
+ /* realpath("") returns CWD */
+ if (!*path) {
+ new_state.cwd = (char*)malloc(1);
+ if (!new_state.cwd) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
+ return NULL;
+ }
+ new_state.cwd[0] = '\0';
+ new_state.cwd_length = 0;
+ if ((cwd = accel_getcwd(&cwd_len TSRMLS_CC)) != NULL) {
+ path = cwd;
+ }
+ } else if (!IS_ABSOLUTE_PATH(path, path_len) &&
+ (cwd = accel_getcwd(&cwd_len TSRMLS_CC)) != NULL) {
+ new_state.cwd = zend_strndup(cwd, cwd_len);
+ if (!new_state.cwd) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
+ return NULL;
+ }
+ new_state.cwd_length = cwd_len;
+ } else {
+ new_state.cwd = (char*)malloc(1);
+ if (!new_state.cwd) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
+ return NULL;
+ }
+ new_state.cwd[0] = '\0';
+ new_state.cwd_length = 0;
+ }
+
+#ifndef CWD_REALPATH
+# define CWD_REALPATH 2
+#endif
+ if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
+ free(new_state.cwd);
+ return NULL;
+ }
+
+ real_path = emalloc(new_state.cwd_length + 1);
+ memcpy(real_path, new_state.cwd, new_state.cwd_length + 1);
+ free(new_state.cwd);
+ return real_path;
+}
+
+static char *accel_php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
+{
+ char *resolved_path;
+ char trypath[MAXPATHLEN];
+ const char *ptr, *end;
+ int len;
+
+ if (!filename) {
+ return NULL;
+ }
+
+ if (*filename == '.' ||
+ IS_ABSOLUTE_PATH(filename, filename_length) ||
+ !path ||
+ !*path) {
+ return accel_tsrm_realpath(filename, filename_length TSRMLS_CC);
+ }
+
+ ptr = path;
+ while (*ptr) {
+ for (end = ptr; *end && *end != DEFAULT_DIR_SEPARATOR; end++);
+ len = end - ptr;
+ if (*end) end++;
+ if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
+ ptr = end;
+ continue;
+ }
+ memcpy(trypath, ptr, len);
+ trypath[len] = '/';
+ memcpy(trypath + len + 1, filename, filename_length + 1);
+ ptr = end;
+ if ((resolved_path = accel_tsrm_realpath(trypath, len + 1 + filename_length TSRMLS_CC)) != NULL) {
+ return resolved_path;
+ }
+ } /* end provided path */
+
+ /* check in calling scripts' current working directory as a fall back case
+ */
+ if (EG(in_execution)) {
+ char *exec_fname = zend_get_executed_filename(TSRMLS_C);
+ int exec_fname_length = strlen(exec_fname);
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+ if (exec_fname && exec_fname[0] != '[' &&
+ exec_fname_length > 0 &&
+ exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
+ memcpy(trypath, exec_fname, exec_fname_length + 1);
+ memcpy(trypath + exec_fname_length + 1, filename, filename_length + 1);
+ return accel_tsrm_realpath(trypath, exec_fname_length + 1 + filename_length TSRMLS_CC);
+ }
+ }
+
+ return NULL;
+}
+
+/* zend_stream_open_function() replacement for PHP 5.2 */
+static int persistent_stream_open_function(const char *filename, zend_file_handle *handle TSRMLS_DC)
+{
+ if (ZCG(enabled) && accel_startup_ok &&
+ (ZCG(counted) || ZCSG(accelerator_enabled)) &&
+ !CG(interactive) &&
+ !ZCSG(restart_in_progress)) {
+
+ if (EG(opline_ptr) && *EG(opline_ptr)) {
+ zend_op *opline = *EG(opline_ptr);
+
+ if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
+ (opline->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
+ opline->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE)) {
+ /* we are in include_once */
+ char *key = NULL;
+ int key_length;
+ char *resolved_path;
+ zend_accel_hash_entry *bucket;
+ zend_persistent_script *persistent_script;
+ int filename_len;
+
+ if (opline->op1.op_type == IS_CONST) {
+ filename_len = Z_STRLEN(opline->op1.u.constant);
+ } else {
+ filename_len = strlen(filename);
+ }
+ handle->filename = (char*)filename;
+ handle->free_filename = 0;
+ handle->opened_path = NULL;
+
+ /* Check if requested file already cached (by full name) */
+ if (IS_ABSOLUTE_PATH(filename, filename_len) &&
+ (persistent_script = zend_accel_hash_find(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL &&
+ !persistent_script->corrupted) {
+
+ handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ handle->type = ZEND_HANDLE_FILENAME;
+ memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
+ ZCG(key_len) = persistent_script->full_path_len;
+ ZCG(cache_opline) = opline;
+ ZCG(cache_persistent_script) = persistent_script;
+ return SUCCESS;
+ }
+
+ /* Check if requested file already cached (by key) */
+ key = accel_make_persistent_key_ex(handle, filename_len, &key_length TSRMLS_CC);
+ if (!ZCG(accel_directives).revalidate_path &&
+ key &&
+ (persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) != NULL &&
+ !persistent_script->corrupted) {
+
+ handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ handle->type = ZEND_HANDLE_FILENAME;
+ ZCG(cache_opline) = opline;
+ ZCG(cache_persistent_script) = persistent_script;
+ return SUCCESS;
+ }
+
+ /* find the full real path */
+ resolved_path = accel_php_resolve_path(filename, filename_len, ZCG(include_path) TSRMLS_CC);
+
+ /* Check if requested file already cached (by real name) */
+ if (resolved_path &&
+ (bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path, strlen(resolved_path) + 1)) != NULL) {
+
+ persistent_script = (zend_persistent_script *)bucket->data;
+ if (persistent_script && !persistent_script->corrupted) {
+ handle->opened_path = resolved_path;
+ handle->type = ZEND_HANDLE_FILENAME;
+ if (key && !ZCG(accel_directives).revalidate_path) {
+ /* add another "key" for the same bucket */
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock(TSRMLS_C);
+ zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
+ zend_shared_alloc_unlock(TSRMLS_C);
+ SHM_PROTECT();
+ }
+ ZCG(cache_opline) = opline;
+ ZCG(cache_persistent_script) = persistent_script;
+ return SUCCESS;
+ }
+ }
+ if (resolved_path) {
+ efree(resolved_path);
+ }
+ }
+ }
+ }
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+ return accelerator_orig_zend_stream_open_function(filename, handle TSRMLS_CC);
+}
+
+#else
+
+/* zend_stream_open_function() replacement for PHP 5.3 and above */
+static int persistent_stream_open_function(const char *filename, zend_file_handle *handle TSRMLS_DC)
+{
+ if (ZCG(enabled) && accel_startup_ok &&
+ (ZCG(counted) || ZCSG(accelerator_enabled)) &&
+ !CG(interactive) &&
+ !ZCSG(restart_in_progress)) {
+
+ /* check if callback is called from include_once or it's a main request */
+ if ((!EG(opline_ptr) &&
+ filename == SG(request_info).path_translated) ||
+ (EG(opline_ptr) &&
+ *EG(opline_ptr) &&
+ (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
+#else
+ ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
+#endif
+
+ /* we are in include_once or FastCGI request */
+ zend_persistent_script *persistent_script;
+
+ handle->filename = (char*)filename;
+ handle->free_filename = 0;
+
+ /* check if cached script was already found by resolve_path() */
+ if ((EG(opline_ptr) == NULL &&
+ ZCG(cache_opline) == NULL &&
+ ZCG(cache_persistent_script) != NULL) ||
+ (EG(opline_ptr) &&
+ (ZCG(cache_opline) == *EG(opline_ptr)))) {
+ persistent_script = ZCG(cache_persistent_script);
+ handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ handle->type = ZEND_HANDLE_FILENAME;
+ return SUCCESS;
+#if 0
+ } else {
+ /* FIXME: It looks like this part is not needed any more */
+ int filename_len = strlen(filename);
+
+ if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
+ is_stream_path(filename)) &&
+ (persistent_script = zend_accel_hash_find(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL &&
+ !persistent_script->corrupted) {
+
+ handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ handle->type = ZEND_HANDLE_FILENAME;
+ memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
+ ZCG(key_len) = persistent_script->full_path_len;
+ ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
+ ZCG(cache_persistent_script) = EG(opline_ptr) ? persistent_script : NULL;
+ return SUCCESS;
+ }
+#endif
+ }
+ }
+ }
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+ return accelerator_orig_zend_stream_open_function(filename, handle TSRMLS_CC);
+}
+
+/* zend_resolve_path() replacement for PHP 5.3 and above */
+static char* persistent_zend_resolve_path(const char *filename, int filename_len TSRMLS_DC)
+{
+ if (ZCG(enabled) && accel_startup_ok &&
+ (ZCG(counted) || ZCSG(accelerator_enabled)) &&
+ !CG(interactive) &&
+ !ZCSG(restart_in_progress)) {
+
+ /* check if callback is called from include_once or it's a main request */
+ if ((!EG(opline_ptr) &&
+ filename == SG(request_info).path_translated) ||
+ (EG(opline_ptr) &&
+ *EG(opline_ptr) &&
+ (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
+#else
+ ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
+ (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
+#endif
+
+ /* we are in include_once or FastCGI request */
+ zend_file_handle handle;
+ char *key = NULL;
+ int key_length;
+ char *resolved_path;
+ zend_accel_hash_entry *bucket;
+ zend_persistent_script *persistent_script;
+
+ /* Check if requested file already cached (by full name) */
+ if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
+ is_stream_path(filename)) &&
+ (bucket = zend_accel_hash_find_entry(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL) {
+ persistent_script = (zend_persistent_script *)bucket->data;
+ if (persistent_script && !persistent_script->corrupted) {
+ memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
+ ZCG(key_len) = persistent_script->full_path_len;
+ ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
+ ZCG(cache_persistent_script) = persistent_script;
+ return estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ }
+ }
+
+ /* Check if requested file already cached (by key) */
+ handle.filename = (char*)filename;
+ handle.free_filename = 0;
+ handle.opened_path = NULL;
+ key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC);
+ if (!ZCG(accel_directives).revalidate_path &&
+ key &&
+ (persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) != NULL &&
+ !persistent_script->corrupted) {
+
+ /* we have persistent script */
+ ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
+ ZCG(cache_persistent_script) = persistent_script;
+ return estrndup(persistent_script->full_path, persistent_script->full_path_len);
+ }
+
+ /* find the full real path */
+ resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
+
+ /* Check if requested file already cached (by real path) */
+ if (resolved_path &&
+ (bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path, strlen(resolved_path) + 1)) != NULL) {
+ persistent_script = (zend_persistent_script *)bucket->data;
+
+ if (persistent_script && !persistent_script->corrupted) {
+ if (key && !ZCG(accel_directives).revalidate_path) {
+ /* add another "key" for the same bucket */
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock(TSRMLS_C);
+ zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
+ zend_shared_alloc_unlock(TSRMLS_C);
+ SHM_PROTECT();
+ }
+ ZCG(cache_opline) = (EG(opline_ptr) && key) ? *EG(opline_ptr): NULL;
+ ZCG(cache_persistent_script) = key ? persistent_script : NULL;
+ return resolved_path;
+ }
+ }
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+ return resolved_path;
+ }
+ }
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+ return accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
+}
+
+#endif
+
+static void zend_reset_cache_vars(TSRMLS_D)
+{
+ ZSMMG(memory_exhausted) = 0;
+ ZCSG(hits) = 0;
+ ZCSG(misses) = 0;
+ ZCSG(blacklist_misses) = 0;
+ ZSMMG(wasted_shared_memory) = 0;
+ ZCSG(restart_pending) = 0;
+ ZCSG(force_restart_time) = 0;
+}
+
+static void accel_activate(void)
+{
+ TSRMLS_FETCH();
+
+ if (!ZCG(enabled) || !accel_startup_ok) {
+ return;
+ }
+
+ SHM_UNPROTECT();
+ /* PHP-5.4 and above return "double", but we use 1 sec precision */
+ ZCG(request_time) = (time_t)sapi_get_request_time(TSRMLS_C);
+ ZCG(cache_opline) = NULL;
+ ZCG(cache_persistent_script) = NULL;
+ ZCG(include_path_check) = !ZCG(include_path_key);
+
+ if (ZCG(counted)) {
+#ifdef ZTS
+ zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
+#else
+ zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
+#endif
+ accel_unlock_all(TSRMLS_C);
+ ZCG(counted) = 0;
+ }
+
+ if (ZCSG(restart_pending)) {
+ zend_shared_alloc_lock(TSRMLS_C);
+ if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
+ if (accel_is_inactive(TSRMLS_C) == SUCCESS) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
+ ZCSG(restart_pending) = 0;
+ switch ZCSG(restart_reason) {
+ case ACCEL_RESTART_OOM:
+ ZCSG(oom_restarts)++;
+ break;
+ case ACCEL_RESTART_WASTED:
+ ZCSG(wasted_restarts)++;
+ break;
+ case ACCEL_RESTART_HASH:
+ ZCSG(hash_restarts)++;
+ break;
+ case ACCEL_RESTART_USER:
+ ZCSG(manual_restarts)++;
+ break;
+ }
+ accel_restart_enter(TSRMLS_C);
+
+ zend_reset_cache_vars(TSRMLS_C);
+ zend_accel_hash_clean(&ZCSG(hash));
+
+ /* include_paths keeps only the first path */
+ if (ZCSG(include_paths).num_entries > 1) {
+ ZCSG(include_paths).num_entries = 1;
+ ZCSG(include_paths).num_direct_entries = 1;
+ memset(ZCSG(include_paths).hash_table, 0, sizeof(zend_accel_hash_entry*) * ZCSG(include_paths).max_num_entries);
+ ZCSG(include_paths).hash_table[zend_inline_hash_func(ZCSG(include_paths).hash_entries[0].key, ZCSG(include_paths).hash_entries[0].key_length) % ZCSG(include_paths).max_num_entries] = &ZCSG(include_paths).hash_entries[0];
+ }
+
+#if (ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO) && !defined(ZTS)
+ accel_interned_strings_restore_state(TSRMLS_C);
+#endif
+
+ zend_shared_alloc_restore_state();
+ ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
+ ZCSG(last_restart_time) = ZCG(request_time);
+ accel_restart_leave(TSRMLS_C);
+ }
+ }
+ zend_shared_alloc_unlock(TSRMLS_C);
+ }
+
+ /* check if ZCG(function_table) wasn't somehow polluted on the way */
+ if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
+ }
+
+ if (ZCG(accel_directives).validate_timestamps) {
+ time_t now = ZCG(request_time);
+ if (now > ZCSG(revalidate_at) + (time_t)ZCG(accel_directives).revalidate_freq) {
+ ZCSG(revalidate_at) = now;
+ }
+ }
+
+ ZCG(cwd) = NULL;
+
+ SHM_PROTECT();
+}
+
+#if !ZEND_DEBUG
+
+/* Fast Request Shutdown
+ * =====================
+ * Zend Memory Manager frees memory by its own. We don't have to free each
+ * allocated block separately, but we like to call all the destructors and
+ * callbacks in exactly the same order.
+ */
+
+static void accel_fast_hash_destroy(HashTable *ht)
+{
+ Bucket *p = ht->pListHead;
+
+ while (p != NULL) {
+ ht->pDestructor(p->pData);
+ p = p->pListNext;
+ }
+}
+
+static void accel_fast_zval_ptr_dtor(zval **zval_ptr)
+{
+ zval *zvalue = *zval_ptr;
+
+ if (Z_DELREF_P(zvalue) == 0) {
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
+#else
+ switch (Z_TYPE_P(zvalue) & ~IS_CONSTANT_INDEX) {
+#endif
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY: {
+ TSRMLS_FETCH();
+
+ if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) {
+ zvalue->value.ht->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ accel_fast_hash_destroy(zvalue->value.ht);
+ }
+ }
+ break;
+ case IS_OBJECT:
+ {
+ TSRMLS_FETCH();
+
+ Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
+ }
+ break;
+ case IS_RESOURCE:
+ {
+ TSRMLS_FETCH();
+
+ /* destroy resource */
+ zend_list_delete(zvalue->value.lval);
+ }
+ break;
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_NULL:
+ case IS_STRING:
+ case IS_CONSTANT:
+ default:
+ return;
+ break;
+ }
+ }
+}
+
+static int accel_clean_non_persistent_function(zend_function *function TSRMLS_DC)
+{
+ if (function->type == ZEND_INTERNAL_FUNCTION) {
+ return ZEND_HASH_APPLY_STOP;
+ } else {
+ if (function->op_array.static_variables) {
+ function->op_array.static_variables->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ accel_fast_hash_destroy(function->op_array.static_variables);
+ function->op_array.static_variables = NULL;
+ }
+ return (--(*function->op_array.refcount) <= 0) ?
+ ZEND_HASH_APPLY_REMOVE :
+ ZEND_HASH_APPLY_KEEP;
+ }
+}
+
+static int accel_cleanup_function_data(zend_function *function TSRMLS_DC)
+{
+ if (function->type == ZEND_USER_FUNCTION) {
+ if (function->op_array.static_variables) {
+ function->op_array.static_variables->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ accel_fast_hash_destroy(function->op_array.static_variables);
+ function->op_array.static_variables = NULL;
+ }
+ }
+ return 0;
+}
+
+static int accel_clean_non_persistent_class(zend_class_entry **pce TSRMLS_DC)
+{
+ zend_class_entry *ce = *pce;
+
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ return ZEND_HASH_APPLY_STOP;
+ } else {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
+ zend_hash_apply(&ce->function_table, (apply_func_t) accel_cleanup_function_data TSRMLS_CC);
+ }
+ if (ce->static_members_table) {
+ int i;
+
+ for (i = 0; i < ce->default_static_members_count; i++) {
+ if (ce->static_members_table[i]) {
+ accel_fast_zval_ptr_dtor(&ce->static_members_table[i]);
+ ce->static_members_table[i] = NULL;
+ }
+ }
+ ce->static_members_table = NULL;
+ }
+#else
+ zend_hash_apply(&ce->function_table, (apply_func_t) accel_cleanup_function_data TSRMLS_CC);
+ if (ce->static_members) {
+ ce->static_members->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ accel_fast_hash_destroy(ce->static_members);
+ ce->static_members = NULL;
+ }
+#endif
+ return ZEND_HASH_APPLY_REMOVE;
+ }
+}
+
+static int accel_clean_non_persistent_constant(zend_constant *c TSRMLS_DC)
+{
+ if (c->flags & CONST_PERSISTENT) {
+ return ZEND_HASH_APPLY_STOP;
+ } else {
+ interned_free(c->name);
+ return ZEND_HASH_APPLY_REMOVE;
+ }
+}
+
+static void zend_accel_fast_shutdown(TSRMLS_D)
+{
+ if (EG(full_tables_cleanup)) {
+ EG(symbol_table).pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ } else {
+ dtor_func_t old_destructor;
+
+ if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
+ /* We don't have to destroy all zvals if they cannot call any destructors */
+
+ old_destructor = EG(symbol_table).pDestructor;
+ EG(symbol_table).pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
+ zend_try {
+ zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+ } zend_end_try();
+ EG(symbol_table).pDestructor = old_destructor;
+ }
+ zend_hash_init(&EG(symbol_table), 0, NULL, NULL, 0);
+ old_destructor = EG(function_table)->pDestructor;
+ EG(function_table)->pDestructor = NULL;
+ zend_hash_reverse_apply(EG(function_table), (apply_func_t) accel_clean_non_persistent_function TSRMLS_CC);
+ EG(function_table)->pDestructor = old_destructor;
+ old_destructor = EG(class_table)->pDestructor;
+ EG(class_table)->pDestructor = NULL;
+ zend_hash_reverse_apply(EG(class_table), (apply_func_t) accel_clean_non_persistent_class TSRMLS_CC);
+ EG(class_table)->pDestructor = old_destructor;
+ old_destructor = EG(zend_constants)->pDestructor;
+ EG(zend_constants)->pDestructor = NULL;
+ zend_hash_reverse_apply(EG(zend_constants), (apply_func_t) accel_clean_non_persistent_constant TSRMLS_CC);
+ EG(zend_constants)->pDestructor = old_destructor;
+ }
+ CG(unclean_shutdown) = 1;
+}
+#endif
+
+static void accel_deactivate(void)
+{
+ /* ensure that we restore function_table and class_table
+ * In general, they're restored by persistent_compile_file(), but in case
+ * the script is aborted abnormally, they may become messed up.
+ */
+ TSRMLS_FETCH();
+
+ if (!ZCG(enabled) || !accel_startup_ok) {
+ return;
+ }
+
+ zend_shared_alloc_safe_unlock(TSRMLS_C); /* be sure we didn't leave cache locked */
+ accel_unlock_all(TSRMLS_C);
+ ZCG(counted) = 0;
+
+#if !ZEND_DEBUG
+ if (ZCG(accel_directives).fast_shutdown) {
+ zend_accel_fast_shutdown(TSRMLS_C);
+ }
+#endif
+
+ if (ZCG(cwd)) {
+ efree(ZCG(cwd));
+ ZCG(cwd) = NULL;
+ }
+
+}
+
+static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
+{
+ (void)element2; /* keep the compiler happy */
+
+ if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
+ element1->startup = NULL;
+#if 0
+ /* We have to call shutdown callback it to free TS resources */
+ element1->shutdown = NULL;
+#endif
+ element1->activate = NULL;
+ element1->deactivate = NULL;
+ element1->op_array_handler = NULL;
+
+#ifdef __DEBUG_MESSAGES__
+ fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
+ fflush(stderr);
+#endif
+ }
+
+ return 0;
+}
+
+static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *) TSRMLS_DC)
+{
+ accel_startup_ok = 0;
+ zps_failure_reason = reason;
+ zps_api_failure_reason = api_reason?api_reason:reason;
+ zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
+}
+
+static inline int accel_find_sapi(TSRMLS_D)
+{
+ static const char *supported_sapis[] = {
+ "apache",
+ "fastcgi",
+ "cli-server",
+ "cgi-fcgi",
+ "fpm-fcgi",
+ "isapi",
+ "apache2filter",
+ "apache2handler",
+ NULL
+ };
+ const char **sapi_name;
+
+ if (sapi_module.name) {
+ for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
+ if (strcmp(sapi_module.name, *sapi_name) == 0) {
+ return SUCCESS;
+ }
+ }
+ if (ZCG(accel_directives).enable_cli &&
+ strcmp(sapi_module.name, "cli") == 0) {
+ return SUCCESS;
+ }
+ }
+
+ return FAILURE;
+}
+
+static void zend_accel_init_shm(TSRMLS_D)
+{
+ zend_shared_alloc_lock(TSRMLS_C);
+
+ accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
+ if (!accel_shared_globals) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ return;
+ }
+ ZSMMG(app_shared_globals) = accel_shared_globals;
+
+ zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
+ zend_accel_hash_init(&ZCSG(include_paths), 32);
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+
+# ifndef ZTS
+ zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1);
+ ZCSG(interned_strings).nTableMask = ZCSG(interned_strings).nTableSize - 1;
+ ZCSG(interned_strings).arBuckets = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
+ ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
+ if (!ZCSG(interned_strings).arBuckets || !ZCSG(interned_strings_start)) {
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
+ }
+ ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
+ ZCSG(interned_strings_top) = ZCSG(interned_strings_start);
+# else
+ ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL;
+# endif
+
+ orig_interned_strings_start = CG(interned_strings_start);
+ orig_interned_strings_end = CG(interned_strings_end);
+ orig_new_interned_string = zend_new_interned_string;
+ orig_interned_strings_snapshot = zend_interned_strings_snapshot;
+ orig_interned_strings_restore = zend_interned_strings_restore;
+
+ CG(interned_strings_start) = ZCSG(interned_strings_start);
+ CG(interned_strings_end) = ZCSG(interned_strings_end);
+ zend_new_interned_string = accel_new_interned_string_for_php;
+ zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
+ zend_interned_strings_restore = accel_interned_strings_restore_for_php;
+
+# ifndef ZTS
+ accel_use_shm_interned_strings(TSRMLS_C);
+ accel_interned_strings_save_state(TSRMLS_C);
+# endif
+
+#endif
+
+ zend_reset_cache_vars(TSRMLS_C);
+
+ ZCSG(oom_restarts) = 0;
+ ZCSG(wasted_restarts) = 0;
+ ZCSG(hash_restarts) = 0;
+ ZCSG(manual_restarts) = 0;
+
+ ZCSG(accelerator_enabled) = 1;
+ ZCSG(last_restart_time) = zend_accel_get_time();
+ ZCSG(restart_in_progress) = 0;
+
+ zend_shared_alloc_unlock(TSRMLS_C);
+}
+
+static void accel_globals_ctor(zend_accel_globals *accel_globals TSRMLS_DC)
+{
+ memset(accel_globals, 0, sizeof(zend_accel_globals));
+ zend_hash_init(&accel_globals->function_table, zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
+ zend_accel_copy_internal_functions(TSRMLS_C);
+}
+
+static void accel_globals_dtor(zend_accel_globals *accel_globals TSRMLS_DC)
+{
+ accel_globals->function_table.pDestructor = NULL;
+ zend_hash_destroy(&accel_globals->function_table);
+}
+
+static int accel_startup(zend_extension *extension)
+{
+ zend_function *func;
+ zend_ini_entry *ini_entry;
+ TSRMLS_FETCH();
+
+#ifdef ZTS
+ accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
+#else
+ accel_globals_ctor(&accel_globals);
+#endif
+
+#ifdef ZEND_WIN32
+ _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
+#endif
+
+ if (start_accel_module() == FAILURE) {
+ accel_startup_ok = 0;
+ zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
+ return FAILURE;
+ }
+
+ /* no supported SAPI found - disable acceleration and stop initialization */
+ if (accel_find_sapi(TSRMLS_C) == FAILURE) {
+ accel_startup_ok = 0;
+ if (!ZCG(accel_directives).enable_cli &&
+ strcmp(sapi_module.name, "cli") == 0) {
+ zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb TSRMLS_CC);
+ } else {
+ zps_startup_failure("Opcode Caching is only supported in Apache, ISAPI, FPM and FastCGI SAPIs", NULL, accelerator_remove_cb TSRMLS_CC);
+ }
+ return SUCCESS;
+ }
+
+ if (ZCG(enabled) == 0) {
+ return SUCCESS ;
+ }
+/********************************************/
+/* End of non-SHM dependent initializations */
+/********************************************/
+ switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
+ case ALLOC_SUCCESS:
+ zend_accel_init_shm(TSRMLS_C);
+ break;
+ case ALLOC_FAILURE:
+ accel_startup_ok = 0;
+ zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
+ return SUCCESS;
+ case SUCCESSFULLY_REATTACHED:
+ accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ zend_shared_alloc_lock(TSRMLS_C);
+ orig_interned_strings_start = CG(interned_strings_start);
+ orig_interned_strings_end = CG(interned_strings_end);
+ orig_new_interned_string = zend_new_interned_string;
+ orig_interned_strings_snapshot = zend_interned_strings_snapshot;
+ orig_interned_strings_restore = zend_interned_strings_restore;
+
+ CG(interned_strings_start) = ZCSG(interned_strings_start);
+ CG(interned_strings_end) = ZCSG(interned_strings_end);
+ zend_new_interned_string = accel_new_interned_string_for_php;
+ zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
+ zend_interned_strings_restore = accel_interned_strings_restore_for_php;
+
+# ifndef ZTS
+ accel_use_shm_interned_strings(TSRMLS_C);
+# endif
+
+ zend_shared_alloc_unlock(TSRMLS_C);
+#endif
+
+ break;
+ case FAILED_REATTACHED:
+ accel_startup_ok = 0;
+ zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
+ return SUCCESS;
+ break;
+ }
+
+ /* from this point further, shared memory is supposed to be OK */
+
+ /* Override compiler */
+ accelerator_orig_compile_file = zend_compile_file;
+ zend_compile_file = persistent_compile_file;
+
+ /* Override stream opener function (to eliminate open() call caused by
+ * include/require statements ) */
+ accelerator_orig_zend_stream_open_function = zend_stream_open_function;
+ zend_stream_open_function = persistent_stream_open_function;
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ /* Override path resolver function (to eliminate stat() calls caused by
+ * include_once/require_once statements */
+ accelerator_orig_zend_resolve_path = zend_resolve_path;
+ zend_resolve_path = persistent_zend_resolve_path;
+#endif
+
+ if (ZCG(accel_directives).validate_timestamps) {
+ ZCSG(revalidate_at) = zend_accel_get_time() + ZCG(accel_directives).revalidate_freq;
+ }
+
+ /* Override chdir() function */
+ if (zend_hash_find(CG(function_table), "chdir", sizeof("chdir"), (void**)&func) == SUCCESS &&
+ func->type == ZEND_INTERNAL_FUNCTION) {
+ orig_chdir = func->internal_function.handler;
+ func->internal_function.handler = ZEND_FN(accel_chdir);
+ }
+ ZCG(cwd) = NULL;
+
+ /* Override "include_path" modifier callback */
+ if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) {
+ ZCG(include_path) = INI_STR("include_path");
+ ZCG(include_path_key) = NULL;
+ if (ZCG(include_path) && *ZCG(include_path)) {
+ ZCG(include_path_len) = strlen(ZCG(include_path));
+ if (!zend_accel_hash_is_full(&ZCSG(include_paths))) {
+ char *key;
+
+ zend_shared_alloc_lock(TSRMLS_C);
+ key = zend_shared_alloc(ZCG(include_path_len) + 2);
+ if (key) {
+ memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
+ key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
+ ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
+ zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
+ }
+ zend_shared_alloc_unlock(TSRMLS_C);
+ }
+ } else {
+ ZCG(include_path) = "";
+ ZCG(include_path_len) = 0;
+ }
+ orig_include_path_on_modify = ini_entry->on_modify;
+ ini_entry->on_modify = accel_include_path_on_modify;
+ }
+
+ zend_shared_alloc_lock(TSRMLS_C);
+ zend_shared_alloc_save_state();
+ zend_shared_alloc_unlock(TSRMLS_C);
+
+ SHM_PROTECT();
+
+ accel_startup_ok = 1;
+
+ /* Override file_exists(), is_file() and is_readable() */
+ zend_accel_override_file_functions(TSRMLS_C);
+
+ /* Load black list */
+ accel_blacklist.entries = NULL;
+ if (ZCG(enabled) && accel_startup_ok &&
+ ZCG(accel_directives).user_blacklist_filename &&
+ *ZCG(accel_directives.user_blacklist_filename)) {
+ zend_accel_blacklist_init(&accel_blacklist);
+ zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
+ }
+
+#if 0
+ /* FIXME: We probably don't need it here */
+ zend_accel_copy_internal_functions(TSRMLS_C);
+#endif
+
+ return SUCCESS;
+}
+
+static void accel_free_ts_resources()
+{
+#ifndef ZTS
+ accel_globals_dtor(&accel_globals);
+#else
+ ts_free_id(accel_globals_id);
+#endif
+}
+
+static void accel_shutdown(zend_extension *extension)
+{
+ zend_ini_entry *ini_entry;
+ TSRMLS_FETCH();
+
+ (void)extension; /* keep the compiler happy */
+
+ zend_accel_blacklist_shutdown(&accel_blacklist);
+
+ if (!ZCG(enabled) || !accel_startup_ok) {
+ accel_free_ts_resources();
+ return;
+ }
+
+ accel_free_ts_resources();
+ zend_shared_alloc_shutdown();
+ zend_compile_file = accelerator_orig_compile_file;
+
+ if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) {
+ ini_entry->on_modify = orig_include_path_on_modify;
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ CG(interned_strings_start) = orig_interned_strings_start;
+ CG(interned_strings_end) = orig_interned_strings_end;
+ zend_new_interned_string = orig_new_interned_string;
+ zend_interned_strings_snapshot = orig_interned_strings_snapshot;
+ zend_interned_strings_restore = orig_interned_strings_restore;
+#endif
+
+}
+
+void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC)
+{
+ if (ZCSG(restart_pending)) {
+ /* don't schedule twice */
+ return;
+ }
+ zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
+
+ ZCSG(restart_pending) = 1;
+ ZCSG(restart_reason) = reason;
+ ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
+ ZCSG(accelerator_enabled) = 0;
+
+ if (ZCG(accel_directives).force_restart_timeout) {
+ ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
+ } else {
+ ZCSG(force_restart_time) = 0;
+ }
+}
+
+/* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
+#ifdef ZEND_WIN32
+#define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub(TSRMLS_C)
+#else
+#define accel_deactivate_now() accel_deactivate_sub(TSRMLS_C)
+#endif
+
+/* ensures it is OK to read SHM
+ if it's not OK (restart in progress) returns FAILURE
+ if OK returns SUCCESS
+ MUST call accelerator_shm_read_unlock after done lock operations
+*/
+int accelerator_shm_read_lock(TSRMLS_D)
+{
+ if (ZCG(counted)) {
+ /* counted means we are holding read lock for SHM, so that nothing bad can happen */
+ return SUCCESS;
+ } else {
+ /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
+ or is in progress now */
+ accel_activate_add(TSRMLS_C); /* acquire usage lock */
+ /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
+ if (ZCSG(restart_in_progress)) {
+ /* we already were inside restart this means it's not safe to touch shm */
+ accel_deactivate_now(); /* drop usage lock */
+ return FAILURE;
+ }
+ }
+ return SUCCESS;
+}
+
+/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
+void accelerator_shm_read_unlock(TSRMLS_D)
+{
+ if (!ZCG(counted)) {
+ /* counted is 0 - meaning we had to readlock manually, release readlock now */
+ accel_deactivate_now();
+ }
+}
+
+static void accel_op_array_handler(zend_op_array *op_array)
+{
+ TSRMLS_FETCH();
+
+ if (ZCG(enabled) && accel_startup_ok && ZCSG(accelerator_enabled)) {
+ zend_optimizer(op_array TSRMLS_CC);
+ }
+}
+
+ZEND_EXT_API zend_extension zend_extension_entry = {
+ ACCELERATOR_PRODUCT_NAME, /* name */
+ ACCELERATOR_VERSION, /* version */
+ "Zend Technologies", /* author */
+ "http://www.zend.com/", /* URL */
+ "Copyright (c) 1999-2013", /* copyright */
+ accel_startup, /* startup */
+ accel_shutdown, /* shutdown */
+ accel_activate, /* per-script activation */
+ accel_deactivate, /* per-script deactivation */
+ NULL, /* message handler */
+ accel_op_array_handler, /* op_array handler */
+ NULL, /* extended statement handler */
+ NULL, /* extended fcall begin handler */
+ NULL, /* extended fcall end handler */
+ NULL, /* op_array ctor */
+ NULL, /* op_array dtor */
+ STANDARD_ZEND_EXTENSION_PROPERTIES
+};
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
new file mode 100644
index 000000000..3f10630ac
--- /dev/null
+++ b/ext/opcache/ZendAccelerator.h
@@ -0,0 +1,382 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_H
+#define ZEND_ACCELERATOR_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define ACCELERATOR_PRODUCT_NAME "Zend OPcache"
+#define ACCELERATOR_VERSION "7.0.1-dev"
+/* 2 - added Profiler support, on 20010712 */
+/* 3 - added support for Optimizer's encoded-only-files mode */
+/* 4 - works with the new Optimizer, that supports the file format with licenses */
+/* 5 - API 4 didn't really work with the license-enabled file format. v5 does. */
+/* 6 - Monitor was removed from ZendPlatform.so, to a module of its own */
+/* 7 - Optimizer was embedded into Accelerator */
+/* 8 - Standalone Open Source Zend OPcache */
+#define ACCELERATOR_API_NO 8
+
+#if ZEND_WIN32
+# include "zend_config.w32.h"
+#else
+#include "zend_config.h"
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include "unistd.h"
+#endif
+
+#include "zend_extensions.h"
+#include "zend_compile.h"
+
+#include "Optimizer/zend_optimizer.h"
+#include "zend_accelerator_hash.h"
+#include "zend_accelerator_debug.h"
+
+#ifndef PHPAPI
+# ifdef ZEND_WIN32
+# define PHPAPI __declspec(dllimport)
+# else
+# define PHPAPI
+# endif
+#endif
+
+#ifndef ZEND_EXT_API
+# if WIN32|WINNT
+# define ZEND_EXT_API __declspec(dllexport)
+# elif defined(__GNUC__) && __GNUC__ >= 4
+# define ZEND_EXT_API __attribute__ ((visibility("default")))
+# else
+# define ZEND_EXT_API
+# endif
+#endif
+
+#ifdef ZEND_WIN32
+# ifndef MAXPATHLEN
+# define MAXPATHLEN _MAX_PATH
+# endif
+# include <direct.h>
+#else
+# include <sys/param.h>
+#endif
+
+#define PHP_5_0_X_API_NO 220040412
+#define PHP_5_1_X_API_NO 220051025
+#define PHP_5_2_X_API_NO 220060519
+#define PHP_5_3_X_API_NO 220090626
+#define PHP_5_4_X_API_NO 220100525
+
+/*** file locking ***/
+#ifndef ZEND_WIN32
+extern int lock_file;
+
+# if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)/* Darwin */) || defined(__OpenBSD__) || defined(__NetBSD__)
+# define FLOCK_STRUCTURE(name, type, whence, start, len) \
+ struct flock name = {start, len, -1, type, whence}
+# elif defined(__svr4__)
+# define FLOCK_STRUCTURE(name, type, whence, start, len) \
+ struct flock name = {type, whence, start, len}
+# elif defined(__linux__) || defined(__hpux)
+# define FLOCK_STRUCTURE(name, type, whence, start, len) \
+ struct flock name = {type, whence, start, len, 0}
+# elif defined(_AIX)
+# if defined(_LARGE_FILES) || defined(__64BIT__)
+# define FLOCK_STRUCTURE(name, type, whence, start, len) \
+ struct flock name = {type, whence, 0, 0, 0, start, len }
+# else
+# define FLOCK_STRUCTURE(name, type, whence, start, len) \
+ struct flock name = {type, whence, start, len}
+# endif
+# else
+# error "Don't know how to define struct flock"
+# endif
+#endif
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ #define Z_REFCOUNT_P(pz) (pz)->refcount
+ #define Z_SET_REFCOUNT_P(pz, v) (pz)->refcount = (v)
+ #define Z_ADDREF_P(pz) ++((pz)->refcount)
+ #define Z_DELREF_P(pz) --((pz)->refcount)
+ #define Z_ISREF_P(pz) (pz)->is_ref
+ #define Z_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1)
+ #define Z_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0)
+ #define Z_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = (isref)
+ #define PZ_REFCOUNT_P(pz) (pz)->refcount
+ #define PZ_SET_REFCOUNT_P(pz, v) (pz)->refcount = (v)
+ #define PZ_ADDREF_P(pz) ++((pz)->refcount)
+ #define PZ_DELREF_P(pz) --((pz)->refcount)
+ #define PZ_ISREF_P(pz) (pz)->is_ref
+ #define PZ_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1)
+ #define PZ_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0)
+ #define PZ_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = (isref)
+#else
+ #define PZ_REFCOUNT_P(pz) (pz)->refcount__gc
+ #define PZ_SET_REFCOUNT_P(pz, v) (pz)->refcount__gc = (v)
+ #define PZ_ADDREF_P(pz) ++((pz)->refcount__gc)
+ #define PZ_DELREF_P(pz) --((pz)->refcount__gc)
+ #define PZ_ISREF_P(pz) (pz)->is_ref__gc
+ #define PZ_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1)
+ #define PZ_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0)
+ #define PZ_SET_ISREF_TO_P(pz, isref) (pz)->is_ref__gc = (isref)
+#endif
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+# ifdef ALLOCA_FLAG
+ #define DO_ALLOCA(x) do_alloca_with_limit(x, use_heap)
+ #define FREE_ALLOCA(x) free_alloca_with_limit(x, use_heap)
+# else
+ #define ALLOCA_FLAG(x)
+ #define DO_ALLOCA(x) do_alloca(x)
+ #define FREE_ALLOCA(x) free_alloca(x)
+# endif
+#else
+ #define DO_ALLOCA(x) do_alloca(x, use_heap)
+ #define FREE_ALLOCA(x) free_alloca(x, use_heap)
+#endif
+
+
+#if ZEND_WIN32
+typedef unsigned __int64 accel_time_t;
+#else
+typedef time_t accel_time_t;
+#endif
+
+typedef enum _zend_accel_restart_reason {
+ ACCEL_RESTART_OOM, /* restart because of out of memory */
+ ACCEL_RESTART_WASTED, /* restart because of wasted memory */
+ ACCEL_RESTART_HASH, /* restart because of hash overflow */
+ ACCEL_RESTART_USER /* restart sheduled by opcache_reset() */
+} zend_accel_restart_reason;
+
+typedef struct _zend_persistent_script {
+ ulong hash_value;
+ char *full_path; /* full real path with resolved symlinks */
+ unsigned int full_path_len;
+ zend_op_array main_op_array;
+ HashTable function_table;
+ HashTable class_table;
+ long compiler_halt_offset; /* position of __HALT_COMPILER or -1 */
+ int ping_auto_globals_mask; /* which autoglobals are used by the script */
+ accel_time_t timestamp; /* the script modification time */
+ zend_bool corrupted;
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ zend_uint early_binding; /* the linked list of delayed declarations */
+#endif
+
+ void *mem; /* shared memory area used by script structures */
+ size_t size; /* size of used shared memory */
+
+ /* All entries that shouldn't be counted in the ADLER32
+ * checksum must be declared in this struct
+ */
+ struct zend_persistent_script_dynamic_members {
+ time_t last_used;
+ ulong hits;
+ unsigned int memory_consumption;
+ unsigned int checksum;
+ time_t revalidate;
+ } dynamic_members;
+} zend_persistent_script;
+
+typedef struct _zend_accel_directives {
+ long memory_consumption;
+ long max_accelerated_files;
+ double max_wasted_percentage;
+ char *user_blacklist_filename;
+ long consistency_checks;
+ long force_restart_timeout;
+ zend_bool use_cwd;
+ zend_bool ignore_dups;
+ zend_bool validate_timestamps;
+ zend_bool revalidate_path;
+ zend_bool save_comments;
+ zend_bool load_comments;
+ zend_bool fast_shutdown;
+ zend_bool protect_memory;
+ zend_bool file_override_enabled;
+ zend_bool inherited_hack;
+ zend_bool enable_cli;
+ unsigned long revalidate_freq;
+ char *error_log;
+#ifdef ZEND_WIN32
+ char *mmap_base;
+#endif
+ char *memory_model;
+ long log_verbosity_level;
+
+ long optimization_level;
+ long max_file_size;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ long interned_strings_buffer;
+#endif
+} zend_accel_directives;
+
+typedef struct _zend_accel_globals {
+ /* copy of CG(function_table) used for compilation scripts into cache */
+ /* initially it contains only internal functions */
+ HashTable function_table;
+ int internal_functions_count;
+ int counted; /* the process uses shared memory */
+ zend_bool enabled;
+ zend_bool locked; /* thread obtained exclusive lock */
+ HashTable bind_hash; /* prototype and zval lookup table */
+ zend_accel_directives accel_directives;
+ char *cwd; /* current working directory or NULL */
+ int cwd_len; /* "cwd" string length */
+ char *include_path_key; /* one letter key of current "include_path" */
+ char *include_path; /* current section of "include_path" directive */
+ int include_path_len; /* "include_path" string length */
+ int include_path_check;
+ time_t request_time;
+ /* preallocated shared-memory block to save current script */
+ void *mem;
+ /* cache to save hash lookup on the same INCLUDE opcode */
+ zend_op *cache_opline;
+ zend_persistent_script *cache_persistent_script;
+ /* preallocated buffer for keys */
+ int key_len;
+ char key[MAXPATHLEN * 8];
+} zend_accel_globals;
+
+typedef struct _zend_accel_shared_globals {
+ /* Cache Data Structures */
+ unsigned long hits;
+ unsigned long misses;
+ unsigned long blacklist_misses;
+ unsigned long oom_restarts; /* number of restarts because of out of memory */
+ unsigned long wasted_restarts; /* number of restarts because of wasted memory */
+ unsigned long hash_restarts; /* number of restarts because of hash overflow */
+ unsigned long manual_restarts; /* number of restarts sheduled by opcache_reset() */
+ zend_accel_hash hash; /* hash table for cached scripts */
+ zend_accel_hash include_paths; /* used "include_path" values */
+
+ /* Directives & Maintenance */
+ time_t last_restart_time;
+ time_t force_restart_time;
+ zend_bool accelerator_enabled;
+ zend_bool restart_pending;
+ zend_accel_restart_reason restart_reason;
+ zend_bool cache_status_before_restart;
+#ifdef ZEND_WIN32
+ unsigned long mem_usage;
+ unsigned long restart_in;
+#endif
+ zend_bool restart_in_progress;
+ time_t revalidate_at;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ /* Interned Strings Support */
+ char *interned_strings_start;
+ char *interned_strings_top;
+ char *interned_strings_end;
+ HashTable interned_strings;
+ struct {
+ Bucket **arBuckets;
+ Bucket *pListHead;
+ Bucket *pListTail;
+ char *top;
+ } interned_strings_saved_state;
+#endif
+} zend_accel_shared_globals;
+
+extern zend_bool accel_startup_ok;
+
+extern zend_accel_shared_globals *accel_shared_globals;
+#define ZCSG(element) (accel_shared_globals->element)
+
+#ifdef ZTS
+# define ZCG(v) TSRMG(accel_globals_id, zend_accel_globals *, v)
+extern int accel_globals_id;
+#else
+# define ZCG(v) (accel_globals.v)
+extern zend_accel_globals accel_globals;
+#endif
+
+extern char *zps_api_failure_reason;
+
+void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC);
+int accelerator_shm_read_lock(TSRMLS_D);
+void accelerator_shm_read_unlock(TSRMLS_D);
+
+char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC);
+
+#if !defined(ZEND_DECLARE_INHERITED_CLASS_DELAYED)
+# define ZEND_DECLARE_INHERITED_CLASS_DELAYED 145
+#endif
+
+#define ZEND_DECLARE_INHERITED_CLASS_DELAYED_FLAG 0x80
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+
+const char *accel_new_interned_string(const char *arKey, int nKeyLength, int free_src TSRMLS_DC);
+
+# define interned_free(s) do { \
+ if (!IS_INTERNED(s)) { \
+ free(s); \
+ } \
+ } while (0)
+# define interned_efree(s) do { \
+ if (!IS_INTERNED(s)) { \
+ efree(s); \
+ } \
+ } while (0)
+# define interned_estrndup(s, n) \
+ (IS_INTERNED(s) ? (s) : estrndup(s, n))
+# define ZEND_RESULT_TYPE(opline) (opline)->result_type
+# define ZEND_RESULT(opline) (opline)->result
+# define ZEND_OP1_TYPE(opline) (opline)->op1_type
+# define ZEND_OP1(opline) (opline)->op1
+# define ZEND_OP1_CONST(opline) (*(opline)->op1.zv)
+# define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant].constant
+# define ZEND_OP2_TYPE(opline) (opline)->op2_type
+# define ZEND_OP2(opline) (opline)->op2
+# define ZEND_OP2_CONST(opline) (*(opline)->op2.zv)
+# define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant].constant
+# define ZEND_DONE_PASS_TWO(op_array) (((op_array)->fn_flags & ZEND_ACC_DONE_PASS_TWO) != 0)
+# define ZEND_CE_FILENAME(ce) (ce)->info.user.filename
+# define ZEND_CE_DOC_COMMENT(ce) (ce)->info.user.doc_comment
+# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->info.user.doc_comment_len
+#else
+# define IS_INTERNED(s) 0
+# define interned_free(s) free(s)
+# define interned_efree(s) efree(s)
+# define interned_estrndup(s, n) estrndup(s, n)
+# define ZEND_RESULT_TYPE(opline) (opline)->result.op_type
+# define ZEND_RESULT(opline) (opline)->result.u
+# define ZEND_OP1_TYPE(opline) (opline)->op1.op_type
+# define ZEND_OP1(opline) (opline)->op1.u
+# define ZEND_OP1_CONST(opline) (opline)->op1.u.constant
+# define ZEND_OP1_LITERAL(opline) (opline)->op1.u.constant
+# define ZEND_OP2_TYPE(opline) (opline)->op2.op_type
+# define ZEND_OP2(opline) (opline)->op2.u
+# define ZEND_OP2_CONST(opline) (opline)->op2.u.constant
+# define ZEND_OP2_LITERAL(opline) (opline)->op2.u.constant
+# define ZEND_DONE_PASS_TWO(op_array) ((op_array)->done_pass_two != 0)
+# define ZEND_CE_FILENAME(ce) (ce)->filename
+# define ZEND_CE_DOC_COMMENT(ce) (ce)->doc_comment
+# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->doc_comment_len
+#endif
+
+#endif /* ZEND_ACCELERATOR_H */
diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4
new file mode 100644
index 000000000..cbf7d5a19
--- /dev/null
+++ b/ext/opcache/config.m4
@@ -0,0 +1,346 @@
+dnl
+dnl $Id$
+dnl
+
+PHP_ARG_ENABLE(opcache, whether to enable Zend OPcache support,
+[ --enable-opcache Enable Zend OPcache support], yes)
+
+if test "$PHP_OPCACHE" != "no"; then
+
+ AC_CHECK_FUNC(mprotect,[
+ AC_DEFINE(HAVE_MPROTECT, 1, [Define if you have mprotect() function])
+ ])
+
+ AC_MSG_CHECKING(for sysvipc shared memory support)
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <unistd.h>
+#include <string.h>
+
+int main() {
+ pid_t pid;
+ int status;
+ int ipc_id;
+ char *shm;
+ struct shmid_ds shmbuf;
+
+ ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W));
+ if (ipc_id == -1) {
+ return 1;
+ }
+
+ shm = shmat(ipc_id, NULL, 0);
+ if (shm == (void *)-1) {
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 2;
+ }
+
+ if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) {
+ shmdt(shm);
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 3;
+ }
+
+ shmbuf.shm_perm.uid = getuid();
+ shmbuf.shm_perm.gid = getgid();
+ shmbuf.shm_perm.mode = 0600;
+
+ if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) {
+ shmdt(shm);
+ shmctl(ipc_id, IPC_RMID, NULL);
+ return 4;
+ }
+
+ shmctl(ipc_id, IPC_RMID, NULL);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+],dnl
+ AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support])
+ msg=yes,msg=no,msg=no)
+ AC_MSG_RESULT([$msg])
+
+ AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support)
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifndef MAP_ANON
+# ifdef MAP_ANONYMOUS
+# define MAP_ANON MAP_ANONYMOUS
+# endif
+#endif
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ char *shm;
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ if (shm == MAP_FAILED) {
+ return 1;
+ }
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+],dnl
+ AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support])
+ msg=yes,msg=no,msg=no)
+ AC_MSG_RESULT([$msg])
+
+ AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support)
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+
+ fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 1;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 2;
+ }
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+],dnl
+ AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support])
+ msg=yes,msg=no,msg=no)
+ AC_MSG_RESULT([$msg])
+
+ AC_MSG_CHECKING(for mmap() using shm_open() shared memory support)
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+ char tmpname[4096];
+
+ sprintf(tmpname,"test.shm.%dXXXXXX", getpid());
+ if (mktemp(tmpname) == NULL) {
+ return 1;
+ }
+ fd = shm_open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 2;
+ }
+ if (ftruncate(fd, 4096) < 0) {
+ close(fd);
+ shm_unlink(tmpname);
+ return 3;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 4;
+ }
+ shm_unlink(tmpname);
+ close(fd);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+],dnl
+ AC_DEFINE(HAVE_SHM_MMAP_POSIX, 1, [Define if you have POSIX mmap() SHM support])
+ msg=yes,msg=no,msg=no)
+ AC_MSG_RESULT([$msg])
+
+ AC_MSG_CHECKING(for mmap() using regular file shared memory support)
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void*)-1)
+#endif
+
+int main() {
+ pid_t pid;
+ int status;
+ int fd;
+ char *shm;
+ char tmpname[4096];
+
+ sprintf(tmpname,"test.shm.%dXXXXXX", getpid());
+ if (mktemp(tmpname) == NULL) {
+ return 1;
+ }
+ fd = open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return 2;
+ }
+ if (ftruncate(fd, 4096) < 0) {
+ close(fd);
+ unlink(tmpname);
+ return 3;
+ }
+
+ shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shm == MAP_FAILED) {
+ return 4;
+ }
+ unlink(tmpname);
+ close(fd);
+
+ strcpy(shm, "hello");
+
+ pid = fork();
+ if (pid < 0) {
+ return 5;
+ } else if (pid == 0) {
+ strcpy(shm, "bye");
+ return 6;
+ }
+ if (wait(&status) != pid) {
+ return 7;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) {
+ return 8;
+ }
+ if (strcmp(shm, "bye") != 0) {
+ return 9;
+ }
+ return 0;
+}
+],dnl
+ AC_DEFINE(HAVE_SHM_MMAP_FILE, 1, [Define if you have mmap() SHM support])
+ msg=yes,msg=no,msg=no)
+ AC_MSG_RESULT([$msg])
+
+ PHP_NEW_EXTENSION(opcache,
+ ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ zend_accelerator_util_funcs.c \
+ shared_alloc_shm.c \
+ shared_alloc_mmap.c \
+ shared_alloc_posix.c \
+ Optimizer/zend_optimizer.c,
+ shared,,,,yes)
+
+ PHP_ADD_BUILD_DIR([$ext_builddir/Optimizer], 1)
+fi
diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32
new file mode 100644
index 000000000..280ce228c
--- /dev/null
+++ b/ext/opcache/config.w32
@@ -0,0 +1,27 @@
+ARG_ENABLE("opcache", "whether to enable Zend OPcache support", "yes");
+
+if (PHP_OPCACHE != "no") {
+
+ PHP_PGI = "no"; // workaround
+ PHP_PGO = "no"; // workaround
+
+ EXTENSION('opcache', "\
+ ZendAccelerator.c \
+ zend_accelerator_blacklist.c \
+ zend_accelerator_debug.c \
+ zend_accelerator_hash.c \
+ zend_accelerator_module.c \
+ zend_accelerator_util_funcs.c \
+ zend_persist.c \
+ zend_persist_calc.c \
+ zend_shared_alloc.c \
+ shared_alloc_win32.c", true);
+
+ ADD_SOURCES(configure_module_dirname + "/Optimizer", "zend_optimizer.c", "opcache", "OptimizerObj");
+
+
+ ADD_FLAG('CFLAGS_OPCACHE', "/I " + configure_module_dirname);
+
+ ADD_FLAG('CFLAGS_OPCACHE', "/Dregexec=php_regexec /Dregerror=php_regerror /Dregfree=php_regfree /Dregcomp=php_regcomp /Iext/ereg/regex");
+
+}
diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c
new file mode 100644
index 000000000..12f00554a
--- /dev/null
+++ b/ext/opcache/shared_alloc_mmap.c
@@ -0,0 +1,78 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend_shared_alloc.h"
+
+#ifdef USE_MMAP
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
+{
+ zend_shared_segment *shared_segment;
+
+ *shared_segments_count = 1;
+ *shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment) + sizeof(void *));
+ if (!*shared_segments_p) {
+ *error_in = "calloc";
+ return ALLOC_FAILURE;
+ }
+ shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
+ (*shared_segments_p)[0] = shared_segment;
+
+ shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (shared_segment->p == MAP_FAILED) {
+ *error_in = "mmap";
+ return ALLOC_FAILURE;
+ }
+
+ shared_segment->pos = 0;
+ shared_segment->size = requested_size;
+
+ return ALLOC_SUCCESS;
+}
+
+static int detach_segment(zend_shared_segment *shared_segment)
+{
+ munmap(shared_segment->p, shared_segment->size);
+ return 0;
+}
+
+static size_t segment_type_size(void)
+{
+ return sizeof(zend_shared_segment);
+}
+
+zend_shared_memory_handlers zend_alloc_mmap_handlers = {
+ create_segments,
+ detach_segment,
+ segment_type_size
+};
+
+#endif /* USE_MMAP */
diff --git a/ext/opcache/shared_alloc_posix.c b/ext/opcache/shared_alloc_posix.c
new file mode 100644
index 000000000..f3377dec6
--- /dev/null
+++ b/ext/opcache/shared_alloc_posix.c
@@ -0,0 +1,98 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend_shared_alloc.h"
+
+#ifdef USE_SHM_OPEN
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+typedef struct {
+ zend_shared_segment common;
+ int shm_fd;
+} zend_shared_segment_posix;
+
+static int create_segments(size_t requested_size, zend_shared_segment_posix ***shared_segments_p, int *shared_segments_count, char **error_in)
+{
+ zend_shared_segment_posix *shared_segment;
+ char shared_segment_name[sizeof("/ZendAccelerator.") + 20];
+
+ *shared_segments_count = 1;
+ *shared_segments_p = (zend_shared_segment_posix **) calloc(1, sizeof(zend_shared_segment_posix) + sizeof(void *));
+ if (!*shared_segments_p) {
+ *error_in = "calloc";
+ return ALLOC_FAILURE;
+ }
+ shared_segment = (zend_shared_segment_posix *)((char *)(*shared_segments_p) + sizeof(void *));
+ (*shared_segments_p)[0] = shared_segment;
+
+ sprintf(shared_segment_name, "/ZendAccelerator.%d", getpid());
+ shared_segment->shm_fd = shm_open(shared_segment_name, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (shared_segment->shm_fd == -1) {
+ *error_in = "shm_open";
+ return ALLOC_FAILURE;
+ }
+
+ if (ftruncate(shared_segment->shm_fd, requested_size) != 0) {
+ *error_in = "ftruncate";
+ shm_unlink(shared_segment_name);
+ return ALLOC_FAILURE;
+ }
+
+ shared_segment->common.p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED, shared_segment->shm_fd, 0);
+ if (shared_segment->common.p == MAP_FAILED) {
+ *error_in = "mmap";
+ shm_unlink(shared_segment_name);
+ return ALLOC_FAILURE;
+ }
+ shm_unlink(shared_segment_name);
+
+ shared_segment->common.pos = 0;
+ shared_segment->common.size = requested_size;
+
+ return ALLOC_SUCCESS;
+}
+
+static int detach_segment(zend_shared_segment_posix *shared_segment)
+{
+ munmap(shared_segment->common.p, shared_segment->common.size);
+ close(shared_segment->shm_fd);
+ return 0;
+}
+
+static size_t segment_type_size(void)
+{
+ return sizeof(zend_shared_segment_posix);
+}
+
+zend_shared_memory_handlers zend_alloc_posix_handlers = {
+ (create_segments_t)create_segments,
+ (detach_segment_t)detach_segment,
+ segment_type_size
+};
+
+#endif /* USE_SHM_OPEN */
diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c
new file mode 100644
index 000000000..d2b842304
--- /dev/null
+++ b/ext/opcache/shared_alloc_shm.c
@@ -0,0 +1,145 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend_shared_alloc.h"
+
+#ifdef USE_SHM
+
+#if defined(__FreeBSD__)
+# include <machine/param.h>
+#endif
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <dirent.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef MIN
+# define MIN(x, y) ((x) > (y)? (y) : (x))
+#endif
+
+#define SEG_ALLOC_SIZE_MAX 32*1024*1024
+#define SEG_ALLOC_SIZE_MIN 2*1024*1024
+
+typedef struct {
+ zend_shared_segment common;
+ int shm_id;
+} zend_shared_segment_shm;
+
+static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in)
+{
+ int i;
+ unsigned int allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size;
+ int first_segment_id = -1;
+ key_t first_segment_key = -1;
+ struct shmid_ds sds;
+ int shmget_flags;
+ zend_shared_segment_shm *shared_segments;
+
+ seg_allocate_size = SEG_ALLOC_SIZE_MAX;
+ /* determine segment size we _really_ need:
+ * no more than to include requested_size
+ */
+ while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) {
+ seg_allocate_size >>= 1;
+ }
+
+ shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL;
+
+ /* try allocating this much, if not - try shrinking */
+ while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) {
+ allocate_size = MIN(requested_size, seg_allocate_size);
+ first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags);
+ if (first_segment_id != -1) {
+ break;
+ }
+ seg_allocate_size >>= 1; /* shrink the allocated block */
+ }
+
+ if (first_segment_id == -1) {
+ *error_in = "shmget";
+ return ALLOC_FAILURE;
+ }
+
+ *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1;
+ *shared_segments_p = (zend_shared_segment_shm **) calloc(1, (*shared_segments_count) * sizeof(zend_shared_segment_shm) + sizeof(void *) * (*shared_segments_count));
+ if (!*shared_segments_p) {
+ *error_in = "calloc";
+ return ALLOC_FAILURE;
+ }
+ shared_segments = (zend_shared_segment_shm *)((char *)(*shared_segments_p) + sizeof(void *) * (*shared_segments_count));
+ for (i = 0; i < *shared_segments_count; i++) {
+ (*shared_segments_p)[i] = shared_segments + i;
+ }
+
+ remaining_bytes = requested_size;
+ for (i = 0; i < *shared_segments_count; i++) {
+ allocate_size = MIN(remaining_bytes, seg_allocate_size);
+ if (i != 0) {
+ shared_segments[i].shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags);
+ } else {
+ shared_segments[i].shm_id = first_segment_id;
+ }
+
+ if (shared_segments[i].shm_id == -1) {
+ return ALLOC_FAILURE;
+ }
+
+ shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0);
+ if (((int) shared_segments[i].common.p) == -1) {
+ *error_in = "shmat";
+ shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
+ return ALLOC_FAILURE;
+ }
+ shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
+
+ shared_segments[i].common.pos = 0;
+ shared_segments[i].common.size = allocate_size;
+ remaining_bytes -= allocate_size;
+ }
+ return ALLOC_SUCCESS;
+}
+
+static int detach_segment(zend_shared_segment_shm *shared_segment)
+{
+ shmdt(shared_segment->common.p);
+ return 0;
+}
+
+static size_t segment_type_size(void)
+{
+ return sizeof(zend_shared_segment_shm);
+}
+
+zend_shared_memory_handlers zend_alloc_shm_handlers = {
+ (create_segments_t)create_segments,
+ (detach_segment_t)detach_segment,
+ segment_type_size
+};
+
+#endif /* USE_SHM */
diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c
new file mode 100644
index 000000000..e32395284
--- /dev/null
+++ b/ext/opcache/shared_alloc_win32.c
@@ -0,0 +1,340 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "ZendAccelerator.h"
+#include "zend_shared_alloc.h"
+#include "zend_accelerator_util_funcs.h"
+#include <winbase.h>
+#include <process.h>
+#include <LMCONS.H>
+
+#define ACCEL_FILEMAP_NAME "ZendOPcache.SharedMemoryArea"
+#define ACCEL_MUTEX_NAME "ZendOPcache.SharedMemoryMutex"
+#define ACCEL_FILEMAP_BASE_DEFAULT 0x01000000
+#define ACCEL_FILEMAP_BASE "ZendOPcache.MemoryBase"
+#define ACCEL_EVENT_SOURCE "Zend OPcache"
+
+static HANDLE memfile = NULL, memory_mutex = NULL;
+static void *mapping_base;
+
+#define MAX_MAP_RETRIES 25
+
+static void zend_win_error_message(int type, char *msg, int err)
+{
+ LPVOID lpMsgBuf;
+ HANDLE h;
+ char *ev_msgs[2];
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ h = RegisterEventSource(NULL, TEXT(ACCEL_EVENT_SOURCE));
+ ev_msgs[0] = msg;
+ ev_msgs[1] = lpMsgBuf;
+ ReportEvent(h, // event log handle
+ EVENTLOG_ERROR_TYPE, // event type
+ 0, // category zero
+ err, // event identifier
+ NULL, // no user security identifier
+ 2, // one substitution string
+ 0, // no data
+ ev_msgs, // pointer to string array
+ NULL); // pointer to data
+ DeregisterEventSource(h);
+
+ LocalFree( lpMsgBuf );
+
+ zend_accel_error(type, msg);
+}
+
+static char *create_name_with_username(char *name)
+{
+ static char newname[MAXPATHLEN + UNLEN + 4];
+ char uname[UNLEN + 1];
+ DWORD unsize = UNLEN;
+
+ GetUserName(uname, &unsize);
+ snprintf(newname, sizeof(newname) - 1, "%s@%s", name, uname);
+ return newname;
+}
+
+static char *get_mmap_base_file(void)
+{
+ static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@")];
+ char uname[UNLEN + 1];
+ DWORD unsize = UNLEN;
+ int l;
+
+ GetTempPath(MAXPATHLEN, windir);
+ GetUserName(uname, &unsize);
+ l = strlen(windir);
+ snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s", ACCEL_FILEMAP_BASE, uname);
+ return windir;
+}
+
+void zend_shared_alloc_create_lock(void)
+{
+ memory_mutex = CreateMutex(NULL, FALSE, create_name_with_username(ACCEL_MUTEX_NAME));
+ if (!memory_mutex) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Cannot create mutex");
+ return;
+ }
+ ReleaseMutex(memory_mutex);
+}
+
+void zend_shared_alloc_lock_win32(void)
+{
+ DWORD waitRes = WaitForSingleObject(memory_mutex, INFINITE);
+
+ if (waitRes == WAIT_FAILED) {
+ zend_accel_error(ACCEL_LOG_ERROR, "Cannot lock mutex");
+ }
+}
+
+void zend_shared_alloc_unlock_win32(void)
+{
+ ReleaseMutex(memory_mutex);
+}
+
+static int zend_shared_alloc_reattach(size_t requested_size, char **error_in)
+{
+ int err;
+ void *wanted_mapping_base;
+ char *mmap_base_file = get_mmap_base_file();
+ FILE *fp = fopen(mmap_base_file, "r");
+ MEMORY_BASIC_INFORMATION info;
+
+ err = GetLastError();
+ if (!fp) {
+ zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err);
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open base address file", err);
+ *error_in="fopen";
+ return ALLOC_FAILURE;
+ }
+ if (!fscanf(fp, "%p", &wanted_mapping_base)) {
+ err = GetLastError();
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to read base address", err);
+ *error_in="read mapping base";
+ fclose(fp);
+ return ALLOC_FAILURE;
+ }
+ fclose(fp);
+
+ /* Check if the requested address space is free */
+ if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0 ||
+ info.State != MEM_FREE ||
+ info.RegionSize < requested_size) {
+ err = ERROR_INVALID_ADDRESS;
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err);
+ return ALLOC_FAILURE;
+ }
+
+ mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base);
+ err = GetLastError();
+
+ if (mapping_base == NULL) {
+ if (err == ERROR_INVALID_ADDRESS) {
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err);
+ return ALLOC_FAILURE;
+ }
+ return ALLOC_FAIL_MAPPING;
+ }
+ smm_shared_globals = (zend_smm_shared_globals *) (((char *) mapping_base) + sizeof(zend_shared_memory_block_header));
+
+ return SUCCESSFULLY_REATTACHED;
+}
+
+static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
+{
+ int err, ret;
+ zend_shared_segment *shared_segment;
+ int map_retries = 0;
+ void *default_mapping_base_set[] = { 0, 0 };
+ void *vista_mapping_base_set[] = { (void *)0x20000000, (void *)0x21000000, (void *)0x30000000, (void *)0x31000000, (void *)0x50000000, 0 };
+ void **wanted_mapping_base = default_mapping_base_set;
+ TSRMLS_FETCH();
+
+ zend_shared_alloc_lock_win32();
+ /* Mapping retries: When Apache2 restarts, the parent process startup routine
+ can be called before the child process is killed. In this case, the map will fail
+ and we have to sleep some time (until the child releases the mapping object) and retry.*/
+ do {
+ memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME));
+ err = GetLastError();
+ if (memfile == NULL) {
+ break;
+ }
+
+ ret = zend_shared_alloc_reattach(requested_size, error_in);
+ err = GetLastError();
+ if (ret == ALLOC_FAIL_MAPPING) {
+ /* Mapping failed, wait for mapping object to get freed and retry */
+ CloseHandle(memfile);
+ memfile = NULL;
+ Sleep(1000 * (map_retries + 1));
+ } else {
+ zend_shared_alloc_unlock_win32();
+ return ret;
+ }
+ } while (++map_retries < MAX_MAP_RETRIES);
+
+ if (map_retries == MAX_MAP_RETRIES) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open file mapping", err);
+ *error_in = "OpenFileMapping";
+ return ALLOC_FAILURE;
+ }
+
+ /* creating segment here */
+ *shared_segments_count = 1;
+ *shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment)+sizeof(void *));
+ if (!*shared_segments_p) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_FATAL, "calloc() failed", GetLastError());
+ *error_in = "calloc";
+ return ALLOC_FAILURE;
+ }
+ shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
+ (*shared_segments_p)[0] = shared_segment;
+
+ memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, requested_size,
+ create_name_with_username(ACCEL_FILEMAP_NAME));
+ err = GetLastError();
+ if (memfile == NULL) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create file mapping", err);
+ *error_in = "CreateFileMapping";
+ return ALLOC_FAILURE;
+ }
+
+ /* Starting from windows Vista, heap randomization occurs which might cause our mapping base to
+ be taken (fail to map). So under Vista, we try to map into a hard coded predefined addresses
+ in high memory. */
+ if (!ZCG(accel_directives).mmap_base || !*ZCG(accel_directives).mmap_base) {
+ do {
+ OSVERSIONINFOEX osvi;
+ SYSTEM_INFO si;
+
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
+ break;
+ }
+ }
+
+ GetSystemInfo(&si);
+
+ /* Are we running Vista ? */
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6) {
+ /* Assert that platform is 32 bit (for 64 bit we need to test a different set */
+ if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) {
+ DebugBreak();
+ }
+
+ wanted_mapping_base = vista_mapping_base_set;
+ }
+ } while (0);
+ } else {
+ char *s = ZCG(accel_directives).mmap_base;
+
+ /* skip leading 0x, %p assumes hexdeciaml format anyway */
+ if (*s == '0' && *(s + 1) == 'x') {
+ s += 2;
+ }
+ if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_FATAL, "Bad mapping address specified in opcache.mmap_base", err);
+ return ALLOC_FAILURE;
+ }
+ }
+
+ do {
+ shared_segment->p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base);
+ if (*wanted_mapping_base == NULL) { /* Auto address (NULL) is the last option on the array */
+ break;
+ }
+ wanted_mapping_base++;
+ } while (!mapping_base);
+
+ err = GetLastError();
+ if (mapping_base == NULL) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create view for file mapping", err);
+ *error_in = "MapViewOfFile";
+ return ALLOC_FAILURE;
+ } else {
+ char *mmap_base_file = get_mmap_base_file();
+ FILE *fp = fopen(mmap_base_file, "w");
+ err = GetLastError();
+ if (!fp) {
+ zend_shared_alloc_unlock_win32();
+ zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err);
+ zend_win_error_message(ACCEL_LOG_FATAL, "Unable to write base address", err);
+ return ALLOC_FAILURE;
+ }
+ fprintf(fp, "%p\n", mapping_base);
+ fclose(fp);
+ }
+
+ shared_segment->pos = 0;
+ shared_segment->size = requested_size;
+
+ zend_shared_alloc_unlock_win32();
+
+ return ALLOC_SUCCESS;
+}
+
+static int detach_segment(zend_shared_segment *shared_segment)
+{
+ zend_shared_alloc_lock_win32();
+ if (mapping_base) {
+ UnmapViewOfFile(mapping_base);
+ }
+ CloseHandle(memfile);
+ zend_shared_alloc_unlock_win32();
+ CloseHandle(memory_mutex);
+ return 0;
+}
+
+static size_t segment_type_size(void)
+{
+ return sizeof(zend_shared_segment);
+}
+
+zend_shared_memory_handlers zend_alloc_win32_handlers = {
+ create_segments,
+ detach_segment,
+ segment_type_size
+};
diff --git a/ext/opcache/tests/001_cli.phpt b/ext/opcache/tests/001_cli.phpt
new file mode 100644
index 000000000..c51db23f5
--- /dev/null
+++ b/ext/opcache/tests/001_cli.phpt
@@ -0,0 +1,19 @@
+--TEST--
+001: O+ works in CLI
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$config = opcache_get_configuration();
+$status = opcache_get_status();
+var_dump($config["directives"]["opcache.enable"]);
+var_dump($config["directives"]["opcache.enable_cli"]);
+var_dump($status["opcache_enabled"]);
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/opcache/tests/bug64353.phpt b/ext/opcache/tests/bug64353.phpt
new file mode 100644
index 000000000..b1f0c6e71
--- /dev/null
+++ b/ext/opcache/tests/bug64353.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #64353 (Built-in classes can be unavailable with dynamic includes and OPcache)
+--INI--
+allow_url_include=1
+opcache.enable=1
+opcache.enable_cli=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class BugLoader extends php_user_filter {
+ public function filter($in, $out, &$consumed, $closing) {
+ if (!class_exists("Test")) {
+ eval("class Test extends ArrayObject {}");
+ }
+ while ($bucket = stream_bucket_make_writeable($in)) {
+ $consumed += $bucket->datalen;
+ stream_bucket_append($out, $bucket);
+ }
+ return PSFS_PASS_ON;
+ }
+}
+
+stream_filter_register('bug.test', 'BugLoader');
+include "php://filter/read=bug.test/resource=data://text/plain,<?php\n";
+echo "OK\n";
+?>
+--EXPECT--
+OK
diff --git a/ext/opcache/tests/issue0057.phpt b/ext/opcache/tests/issue0057.phpt
new file mode 100644
index 000000000..49e9156f1
--- /dev/null
+++ b/ext/opcache/tests/issue0057.phpt
@@ -0,0 +1,38 @@
+--TEST--
+ISSUE #57 (segfaults in drupal7)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+class ZException extends Exception {
+}
+
+function dummy($query) {
+ try {
+ switch ($query) {
+ case 1;
+ break;
+ case 2;
+ break;
+ default:
+ throw new Exception('exception');
+ }
+ } catch (ZException $e) {
+ return NULL;
+ }
+}
+
+try {
+ dummy(0);
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+exception
diff --git a/ext/opcache/tests/skipif.inc b/ext/opcache/tests/skipif.inc
new file mode 100644
index 000000000..c5a818103
--- /dev/null
+++ b/ext/opcache/tests/skipif.inc
@@ -0,0 +1,3 @@
+<?php
+ if (!extension_loaded('Zend OPcache')) die('skip Zend OPcache extension not available');
+?>
diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c
new file mode 100644
index 000000000..0ccd62e34
--- /dev/null
+++ b/ext/opcache/zend_accelerator_blacklist.c
@@ -0,0 +1,261 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "main/php.h"
+#include "main/fopen_wrappers.h"
+#include "ZendAccelerator.h"
+#include "zend_accelerator_blacklist.h"
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+# include "ext/ereg/php_regex.h"
+#else
+# include "main/php_regex.h"
+#endif
+
+#ifdef ZEND_WIN32
+# define REGEX_MODE (REG_EXTENDED|REG_NOSUB|REG_ICASE)
+#else
+# define REGEX_MODE (REG_EXTENDED|REG_NOSUB)
+#endif
+
+#define ZEND_BLACKLIST_BLOCK_SIZE 32
+
+struct _zend_regexp_list {
+ regex_t comp_regex;
+ zend_regexp_list *next;
+};
+
+zend_blacklist accel_blacklist;
+
+void zend_accel_blacklist_init(zend_blacklist *blacklist)
+{
+ blacklist->pos = 0;
+ blacklist->size = ZEND_BLACKLIST_BLOCK_SIZE;
+
+ if (blacklist->entries != NULL) {
+ zend_accel_blacklist_shutdown(blacklist);
+ }
+
+ blacklist->entries = (zend_blacklist_entry *) calloc(sizeof(zend_blacklist_entry), blacklist->size);
+ if (!blacklist->entries) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Blacklist initialization: no memory\n");
+ return;
+ }
+ blacklist->regexp_list = NULL;
+}
+
+static void blacklist_report_regexp_error(regex_t *comp_regex, int reg_err)
+{
+ char *errbuf;
+ int errsize = regerror(reg_err, comp_regex, NULL, 0);
+ errbuf = malloc(errsize);
+ if (!errbuf) {
+ zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: no memory\n");
+ return;
+ }
+ regerror(reg_err, comp_regex, errbuf, errsize);
+ zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: %s\n", errbuf);
+ free(errbuf);
+}
+
+static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist)
+{
+ char *regexp;
+ int i, j, clen, reg_err, end = 0, rlen = 6;
+ zend_regexp_list **regexp_list_it, *it;
+
+ if (blacklist->pos == 0) {
+ /* we have no blacklist to talk about */
+ return;
+ }
+
+ regexp_list_it = &(blacklist->regexp_list);
+ for (i = 0; i < blacklist->pos; i++) {
+ rlen += blacklist->entries[i].path_length * 2 + 2;
+
+ /* don't create a regexp buffer bigger than 12K)*/
+ if ((i + 1 == blacklist->pos) || ((rlen + blacklist->entries[i + 1].path_length * 2 + 2) > (12 * 1024))) {
+ regexp = (char *)malloc(rlen);
+ if (!regexp) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
+ return;
+ }
+ regexp[0] = '^';
+ regexp[1] = '(';
+
+ clen = 2;
+ for (j = end; j <= i; j++) {
+
+ int c;
+ if (j != end) {
+ regexp[clen++] = '|';
+ }
+ /* copy mangled filename */
+ for (c = 0; c < blacklist->entries[j].path_length; c++) {
+ if (strchr("^.[]$()|*+?{}\\", blacklist->entries[j].path[c])) {
+ regexp[clen++] = '\\';
+ }
+ regexp[clen++] = blacklist->entries[j].path[c];
+ }
+ }
+ regexp[clen++] = ')';
+ regexp[clen] = '\0';
+
+ it = (zend_regexp_list*)malloc(sizeof(zend_regexp_list));
+ if (!it) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
+ return;
+ }
+ it->next = NULL;
+
+ if ((reg_err = regcomp(&it->comp_regex, regexp, REGEX_MODE)) != 0) {
+ blacklist_report_regexp_error(&it->comp_regex, reg_err);
+ }
+ /* prepare for the next iteration */
+ free(regexp);
+ end = i + 1;
+ rlen = 6;
+ *regexp_list_it = it;
+ regexp_list_it = &it->next;
+ }
+ }
+}
+
+void zend_accel_blacklist_shutdown(zend_blacklist *blacklist)
+{
+ zend_blacklist_entry *p = blacklist->entries, *end = blacklist->entries + blacklist->pos;
+
+ while (p<end) {
+ free(p->path);
+ p++;
+ }
+ free(blacklist->entries);
+ blacklist->entries = NULL;
+ if (blacklist->regexp_list) {
+ zend_regexp_list *temp, *it = blacklist->regexp_list;
+ while (it) {
+ regfree(&it->comp_regex);
+ temp = it;
+ it = it->next;
+ free(temp);
+ }
+ }
+}
+
+static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist)
+{
+ if (blacklist->pos == blacklist->size) {
+ blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE;
+ blacklist->entries = (zend_blacklist_entry *) realloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size);
+ }
+}
+
+void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename)
+{
+ char buf[MAXPATHLEN + 1], real_path[MAXPATHLEN + 1];
+ FILE *fp;
+ int path_length;
+ TSRMLS_FETCH();
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Cannot load blacklist file: %s\n", filename);
+ return;
+ }
+
+ zend_accel_error(ACCEL_LOG_DEBUG,"Loading blacklist file: '%s'", filename);
+
+ memset(buf, 0, sizeof(buf));
+ memset(real_path, 0, sizeof(real_path));
+
+ while (fgets(buf, MAXPATHLEN, fp) != NULL) {
+ char *path_dup, *pbuf;
+ path_length = strlen(buf);
+ if (path_length > 0 && buf[path_length - 1] == '\n') {
+ buf[--path_length] = 0;
+ if (path_length > 0 && buf[path_length - 1] == '\r') {
+ buf[--path_length] = 0;
+ }
+ }
+
+ /* Strip ctrl-m prefix */
+ pbuf = &buf[0];
+ while (*pbuf == '\r') {
+ *pbuf++ = 0;
+ path_length--;
+ }
+
+ /* strip \" */
+ if (pbuf[0] == '\"' && pbuf[path_length - 1]== '\"') {
+ *pbuf++ = 0;
+ path_length -= 2;
+ }
+
+ if (path_length == 0) {
+ continue;
+ }
+
+ path_dup = zend_strndup(pbuf, path_length);
+ expand_filepath(path_dup, real_path TSRMLS_CC);
+ path_length = strlen(real_path);
+
+ free(path_dup);
+
+ zend_accel_blacklist_allocate(blacklist);
+ blacklist->entries[blacklist->pos].path_length = path_length;
+ blacklist->entries[blacklist->pos].path = (char *)malloc(path_length + 1);
+ if (!blacklist->entries[blacklist->pos].path) {
+ zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
+ return;
+ }
+ blacklist->entries[blacklist->pos].id = blacklist->pos;
+ memcpy(blacklist->entries[blacklist->pos].path, real_path, path_length + 1);
+ blacklist->pos++;
+ }
+ fclose(fp);
+ zend_accel_blacklist_update_regexp(blacklist);
+}
+
+zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path)
+{
+ int ret = 0;
+ zend_regexp_list *regexp_list_it = blacklist->regexp_list;
+
+ if (regexp_list_it == NULL) {
+ return 0;
+ }
+ while (regexp_list_it != NULL) {
+ if (regexec(&(regexp_list_it->comp_regex), verify_path, 0, NULL, 0) == 0) {
+ ret = 1;
+ break;
+ }
+ regexp_list_it = regexp_list_it->next;
+ }
+ return ret;
+}
+
+void zend_accel_blacklist_apply(zend_blacklist *blacklist, apply_func_arg_t func, void *argument TSRMLS_DC)
+{
+ int i;
+
+ for (i = 0; i < blacklist->pos; i++) {
+ func(&blacklist->entries[i], argument TSRMLS_CC);
+ }
+}
diff --git a/ext/opcache/zend_accelerator_blacklist.h b/ext/opcache/zend_accelerator_blacklist.h
new file mode 100644
index 000000000..626b8d2c4
--- /dev/null
+++ b/ext/opcache/zend_accelerator_blacklist.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_BLACKLIST_H
+#define ZEND_ACCELERATOR_BLACKLIST_H
+
+typedef struct _zend_regexp_list zend_regexp_list;
+
+typedef struct _zend_blacklist_entry {
+ char *path;
+ int path_length;
+ int id;
+} zend_blacklist_entry;
+
+typedef struct _zend_blacklist {
+ zend_blacklist_entry *entries;
+ int size;
+ int pos;
+ zend_regexp_list *regexp_list;
+} zend_blacklist;
+
+extern zend_blacklist accel_blacklist;
+
+void zend_accel_blacklist_init(zend_blacklist *blacklist);
+void zend_accel_blacklist_shutdown(zend_blacklist *blacklist);
+
+void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename);
+zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path);
+void zend_accel_blacklist_apply(zend_blacklist *blacklist, apply_func_arg_t func, void *argument TSRMLS_DC);
+
+#endif /* ZEND_ACCELERATOR_BLACKLIST_H */
diff --git a/ext/opcache/zend_accelerator_debug.c b/ext/opcache/zend_accelerator_debug.c
new file mode 100644
index 000000000..93349e3d1
--- /dev/null
+++ b/ext/opcache/zend_accelerator_debug.c
@@ -0,0 +1,99 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#ifdef ZEND_WIN32
+# include <process.h>
+#endif
+#include "ZendAccelerator.h"
+
+void zend_accel_error(int type, const char *format, ...)
+{
+ va_list args;
+ time_t timestamp;
+ char *time_string;
+ FILE * fLog = NULL;
+ TSRMLS_FETCH();
+
+ if (type > ZCG(accel_directives).log_verbosity_level) {
+ return;
+ }
+
+ timestamp = time(NULL);
+ time_string = asctime(localtime(&timestamp));
+ time_string[24] = 0;
+
+ if (!ZCG(accel_directives).error_log ||
+ !*ZCG(accel_directives).error_log ||
+ strcmp(ZCG(accel_directives).error_log, "stderr") == 0) {
+
+ fLog = stderr;
+ } else {
+ fLog = fopen(ZCG(accel_directives).error_log, "a+");
+ if (!fLog) {
+ fLog = stderr;
+ }
+ }
+
+#ifdef ZTS
+ fprintf(fLog, "%s (%lu): ", time_string, (unsigned long)tsrm_thread_id());
+#else
+ fprintf(fLog, "%s (%d): ", time_string, getpid());
+#endif
+
+ switch (type) {
+ case ACCEL_LOG_FATAL:
+ fprintf(fLog, "Fatal Error ");
+ break;
+ case ACCEL_LOG_ERROR:
+ fprintf(fLog, "Error ");
+ break;
+ case ACCEL_LOG_WARNING:
+ fprintf(fLog, "Warning ");
+ break;
+ case ACCEL_LOG_INFO:
+ fprintf(fLog, "Message ");
+ break;
+ case ACCEL_LOG_DEBUG:
+ fprintf(fLog, "Debug ");
+ break;
+ }
+
+ va_start(args, format);
+ vfprintf(fLog, format, args);
+ va_end(args);
+ fprintf(fLog, "\n");
+ switch (type) {
+ case ACCEL_LOG_ERROR:
+ zend_bailout();
+ break;
+ case ACCEL_LOG_FATAL:
+ exit(-2);
+ break;
+ }
+ fflush(fLog);
+ if (fLog != stderr) {
+ fclose(fLog);
+ }
+}
diff --git a/ext/opcache/zend_accelerator_debug.h b/ext/opcache/zend_accelerator_debug.h
new file mode 100644
index 000000000..2ff88e21d
--- /dev/null
+++ b/ext/opcache/zend_accelerator_debug.h
@@ -0,0 +1,33 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_DEBUG_H
+#define ZEND_ACCELERATOR_DEBUG_H
+
+#define ACCEL_LOG_FATAL 0
+#define ACCEL_LOG_ERROR 1
+#define ACCEL_LOG_WARNING 2
+#define ACCEL_LOG_INFO 3
+#define ACCEL_LOG_DEBUG 4
+
+void zend_accel_error(int type, const char *format, ...);
+
+#endif /* _ZEND_ACCELERATOR_DEBUG_H */
diff --git a/ext/opcache/zend_accelerator_hash.c b/ext/opcache/zend_accelerator_hash.c
new file mode 100644
index 000000000..afd227c5d
--- /dev/null
+++ b/ext/opcache/zend_accelerator_hash.c
@@ -0,0 +1,224 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "ZendAccelerator.h"
+#include "zend_accelerator_hash.h"
+#include "zend_hash.h"
+#include "zend_shared_alloc.h"
+
+/* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */
+static uint prime_numbers[] =
+ {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 };
+static uint num_prime_numbers = sizeof(prime_numbers) / sizeof(uint);
+
+void zend_accel_hash_clean(zend_accel_hash *accel_hash)
+{
+ accel_hash->num_entries = 0;
+ accel_hash->num_direct_entries = 0;
+ memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
+}
+
+void zend_accel_hash_init(zend_accel_hash *accel_hash, zend_uint hash_size)
+{
+ uint i;
+
+ for (i=0; i<num_prime_numbers; i++) {
+ if (hash_size <= prime_numbers[i]) {
+ hash_size = prime_numbers[i];
+ break;
+ }
+ }
+
+ accel_hash->num_entries = 0;
+ accel_hash->num_direct_entries = 0;
+ accel_hash->max_num_entries = hash_size;
+
+ /* set up hash pointers table */
+ accel_hash->hash_table = zend_shared_alloc(sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
+ if (!accel_hash->hash_table) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ return;
+ }
+
+ /* set up hash values table */
+ accel_hash->hash_entries = zend_shared_alloc(sizeof(zend_accel_hash_entry)*accel_hash->max_num_entries);
+ if (!accel_hash->hash_entries) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ return;
+ }
+ memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
+}
+
+/* Returns NULL if hash is full
+ * Returns pointer the actual hash entry on success
+ * key needs to be already allocated as it is not copied
+ */
+zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char *key, zend_uint key_length, zend_bool indirect, void *data)
+{
+ zend_ulong hash_value;
+ zend_ulong index;
+ zend_accel_hash_entry *entry;
+ zend_accel_hash_entry *indirect_bucket = NULL;
+
+ if (indirect) {
+ indirect_bucket = (zend_accel_hash_entry*)data;
+ while (indirect_bucket->indirect) {
+ indirect_bucket = (zend_accel_hash_entry*)indirect_bucket->data;
+ }
+ }
+
+ hash_value = zend_inline_hash_func(key, key_length);
+ index = hash_value % accel_hash->max_num_entries;
+
+ /* try to see if the element already exists in the hash */
+ entry = accel_hash->hash_table[index];
+ while (entry) {
+ if (entry->hash_value == hash_value
+ && entry->key_length == key_length
+ && !memcmp(entry->key, key, key_length)) {
+
+ if (entry->indirect) {
+ if (indirect_bucket) {
+ entry->data = indirect_bucket;
+ } else {
+ ((zend_accel_hash_entry*)entry->data)->data = data;
+ }
+ } else {
+ if (indirect_bucket) {
+ accel_hash->num_direct_entries--;
+ entry->data = indirect_bucket;
+ entry->indirect = 1;
+ } else {
+ entry->data = data;
+ }
+ }
+ return entry;
+ }
+ entry = entry->next;
+ }
+
+ /* Does not exist, add a new entry */
+ if (accel_hash->num_entries == accel_hash->max_num_entries) {
+ return NULL;
+ }
+
+ entry = &accel_hash->hash_entries[accel_hash->num_entries++];
+ if (indirect) {
+ entry->data = indirect_bucket;
+ entry->indirect = 1;
+ } else {
+ accel_hash->num_direct_entries++;
+ entry->data = data;
+ entry->indirect = 0;
+ }
+ entry->hash_value = hash_value;
+ entry->key = key;
+ entry->key_length = key_length;
+ entry->next = accel_hash->hash_table[index];
+ accel_hash->hash_table[index] = entry;
+ return entry;
+}
+
+/* Returns the data associated with key on success
+ * Returns NULL if data doesn't exist
+ */
+void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
+{
+ zend_ulong hash_value;
+ zend_ulong index;
+ zend_accel_hash_entry *entry;
+
+ hash_value = zend_inline_hash_func(key, key_length);
+ index = hash_value % accel_hash->max_num_entries;
+
+ entry = accel_hash->hash_table[index];
+ while (entry) {
+ if (entry->hash_value == hash_value
+ && entry->key_length == key_length
+ && !memcmp(entry->key, key, key_length)) {
+ if (entry->indirect) {
+ return ((zend_accel_hash_entry *) entry->data)->data;
+ } else {
+ return entry->data;
+ }
+ }
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+/* Returns the hash entry associated with key on success
+ * Returns NULL if it doesn't exist
+ */
+zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
+{
+ zend_ulong hash_value;
+ zend_ulong index;
+ zend_accel_hash_entry *entry;
+
+ hash_value = zend_inline_hash_func(key, key_length);
+ index = hash_value % accel_hash->max_num_entries;
+
+ entry = accel_hash->hash_table[index];
+ while (entry) {
+ if (entry->hash_value == hash_value
+ && entry->key_length == key_length
+ && !memcmp(entry->key, key, key_length)) {
+ if (entry->indirect) {
+ return (zend_accel_hash_entry *) entry->data;
+ } else {
+ return entry;
+ }
+ }
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
+{
+ zend_ulong hash_value;
+ zend_ulong index;
+ zend_accel_hash_entry *entry, *last_entry=NULL;
+
+ hash_value = zend_inline_hash_func(key, key_length);
+ index = hash_value % accel_hash->max_num_entries;
+
+ entry = accel_hash->hash_table[index];
+ while (entry) {
+ if (entry->hash_value == hash_value
+ && entry->key_length == key_length
+ && !memcmp(entry->key, key, key_length)) {
+ if (!entry->indirect) {
+ accel_hash->num_direct_entries--;
+ }
+ if (last_entry) {
+ last_entry->next = entry->next;
+ } else {
+ accel_hash->hash_table[index] = entry->next;
+ }
+ return SUCCESS;
+ }
+ last_entry = entry;
+ entry = entry->next;
+ }
+ return FAILURE;
+}
diff --git a/ext/opcache/zend_accelerator_hash.h b/ext/opcache/zend_accelerator_hash.h
new file mode 100644
index 000000000..fdfddb406
--- /dev/null
+++ b/ext/opcache/zend_accelerator_hash.h
@@ -0,0 +1,98 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_HASH_H
+#define ZEND_ACCELERATOR_HASH_H
+
+#include "zend.h"
+
+/*
+ zend_accel_hash - is a hash table allocated in shared memory and
+ distributed across simultaneously running processes. The hash tables have
+ fixed sizen selected during construction by zend_accel_hash_init(). All the
+ hash entries are preallocated in the 'hash_entries' array. 'num_entries' is
+ initialized by zero and grows when new data is added.
+ zend_accel_hash_update() just takes the next entry from 'hash_entries'
+ array and puts it into appropriate place of 'hash_table'.
+ Hash collisions are resolved by separate chaining with linked lists,
+ however, entries are still taken from the same 'hash_entries' array.
+ 'key' and 'data' passed to zend_accel_hash_update() must be already
+ allocated in shared memory. Few keys may be resolved to the same data.
+ using 'indirect' entries, that point to other entries ('data' is actually
+ a pointer to another zend_accel_hash_entry).
+ zend_accel_hash_update() requires exclusive lock, however,
+ zend_accel_hash_find() does not.
+*/
+
+typedef struct _zend_accel_hash_entry zend_accel_hash_entry;
+
+struct _zend_accel_hash_entry {
+ zend_ulong hash_value;
+ char *key;
+ zend_uint key_length;
+ zend_accel_hash_entry *next;
+ void *data;
+ zend_bool indirect;
+};
+
+typedef struct _zend_accel_hash {
+ zend_accel_hash_entry **hash_table;
+ zend_accel_hash_entry *hash_entries;
+ zend_uint num_entries;
+ zend_uint max_num_entries;
+ zend_uint num_direct_entries;
+} zend_accel_hash;
+
+void zend_accel_hash_init(zend_accel_hash *accel_hash, zend_uint hash_size);
+void zend_accel_hash_clean(zend_accel_hash *accel_hash);
+
+zend_accel_hash_entry* zend_accel_hash_update(
+ zend_accel_hash *accel_hash,
+ char *key,
+ zend_uint key_length,
+ zend_bool indirect,
+ void *data);
+
+void* zend_accel_hash_find(
+ zend_accel_hash *accel_hash,
+ char *key,
+ zend_uint key_length);
+
+zend_accel_hash_entry* zend_accel_hash_find_entry(
+ zend_accel_hash *accel_hash,
+ char *key,
+ zend_uint key_length);
+
+int zend_accel_hash_unlink(
+ zend_accel_hash *accel_hash,
+ char *key,
+ zend_uint key_length);
+
+static inline zend_bool zend_accel_hash_is_full(zend_accel_hash *accel_hash)
+{
+ if (accel_hash->num_entries == accel_hash->max_num_entries) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#endif /* ZEND_ACCELERATOR_HASH_H */
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
new file mode 100644
index 000000000..778fee54b
--- /dev/null
+++ b/ext/opcache/zend_accelerator_module.c
@@ -0,0 +1,618 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <time.h>
+
+#include "php.h"
+#include "ZendAccelerator.h"
+#include "zend_API.h"
+#include "zend_shared_alloc.h"
+#include "zend_accelerator_blacklist.h"
+#include "php_ini.h"
+#include "SAPI.h"
+#include "TSRM/tsrm_virtual_cwd.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_filestat.h"
+
+#define STRING_NOT_NULL(s) (NULL == (s)?"":s)
+#define MIN_ACCEL_FILES 200
+#define MAX_ACCEL_FILES 100000
+#define TOKENTOSTR(X) #X
+
+static void (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
+static void (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
+static void (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
+
+/* User functions */
+static ZEND_FUNCTION(opcache_reset);
+
+/* Private functions */
+static ZEND_FUNCTION(opcache_get_status);
+static ZEND_FUNCTION(opcache_get_configuration);
+
+static zend_function_entry accel_functions[] = {
+ /* User functions */
+ ZEND_FE(opcache_reset, NULL)
+ /* Private functions */
+ ZEND_FE(opcache_get_configuration, NULL)
+ ZEND_FE(opcache_get_status, NULL)
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static ZEND_INI_MH(OnUpdateMemoryConsumption)
+{
+ long *p;
+ long memsize;
+#ifndef ZTS
+ char *base = (char *) mh_arg2;
+#else
+ char *base = (char *) ts_resource(*((int *) mh_arg2));
+#endif
+
+ /* keep the compiler happy */
+ (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
+
+ p = (long *) (base + (size_t)mh_arg1);
+ memsize = atoi(new_value);
+ /* sanity check we must use at least 8 MB */
+ if (memsize < 8) {
+ const char *new_new_value = "8";
+ zend_ini_entry *ini_entry;
+
+ memsize = 8;
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n");
+ zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal 8MB configuration.\n");
+
+ if (zend_hash_find(EG(ini_directives),
+ "opcache.memory_consumption",
+ sizeof("opcache.memory_consumption"),
+ (void *) &ini_entry) == FAILURE) {
+ return FAILURE;
+ }
+
+ ini_entry->value = strdup(new_new_value);
+ ini_entry->value_length = strlen(new_new_value);
+ }
+ *p = memsize * (1024 * 1024);
+ return SUCCESS;
+}
+
+static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)
+{
+ long *p;
+ long size;
+#ifndef ZTS
+ char *base = (char *) mh_arg2;
+#else
+ char *base = (char *) ts_resource(*((int *) mh_arg2));
+#endif
+
+ /* keep the compiler happy */
+ (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
+
+ p = (long *) (base + (size_t)mh_arg1);
+ size = atoi(new_value);
+ /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */
+
+ if (size < MIN_ACCEL_FILES || size > MAX_ACCEL_FILES) {
+ const char *new_new_value;
+ zend_ini_entry *ini_entry;
+
+ if (size < MIN_ACCEL_FILES) {
+ size = MIN_ACCEL_FILES;
+ new_new_value = TOKENTOSTR(MIN_ACCEL_FILES);
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES);
+ zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal configuration.\n");
+ }
+ if (size > MAX_ACCEL_FILES) {
+ size = MAX_ACCEL_FILES;
+ new_new_value = TOKENTOSTR(MAX_ACCEL_FILES);
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES);
+ zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the maximal configuration.\n");
+ }
+ if (zend_hash_find(EG(ini_directives),
+ "opcache.max_accelerated_files",
+ sizeof("opcache.max_accelerated_files"),
+ (void *) &ini_entry) == FAILURE) {
+ return FAILURE;
+ }
+ ini_entry->value = strdup(new_new_value);
+ ini_entry->value_length = strlen(new_new_value);
+ }
+ *p = size;
+ return SUCCESS;
+}
+
+static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
+{
+ double *p;
+ long percentage;
+#ifndef ZTS
+ char *base = (char *) mh_arg2;
+#else
+ char *base = (char *) ts_resource(*((int *) mh_arg2));
+#endif
+
+ /* keep the compiler happy */
+ (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
+
+ p = (double *) (base + (size_t)mh_arg1);
+ percentage = atoi(new_value);
+
+ if (percentage <= 0 || percentage > 50) {
+ const char *new_new_value = "5";
+ zend_ini_entry *ini_entry;
+
+ percentage = 5;
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
+ zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use 5%.\n");
+ if (zend_hash_find(EG(ini_directives),
+ "opcache.max_wasted_percentage",
+ sizeof("opcache.max_wasted_percentage"),
+ (void *) &ini_entry) == FAILURE) {
+ return FAILURE;
+ }
+ ini_entry->value = strdup(new_new_value);
+ ini_entry->value_length = strlen(new_new_value);
+ }
+ *p = (double)percentage / 100.0;
+ return SUCCESS;
+}
+
+ZEND_INI_BEGIN()
+ STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_SYSTEM, OnUpdateBool, enabled , zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.inherited_hack" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
+
+ STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.memory_consumption" , "64" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "4" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
+#endif
+ STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "2000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals)
+
+ STD_PHP_INI_ENTRY("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.load_comments" , "1" , PHP_INI_ALL, OnUpdateBool, accel_directives.load_comments, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals)
+
+ STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
+
+#ifdef ZEND_WIN32
+ STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals)
+#endif
+ZEND_INI_END()
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+
+#undef EX
+#define EX(element) execute_data->element
+#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
+
+static int ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_class_entry **pce, **pce_orig;
+
+ if (zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op2.u.constant), Z_STRLEN(EX(opline)->op2.u.constant) + 1, (void **)&pce) == FAILURE ||
+ (zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op1.u.constant), Z_STRLEN(EX(opline)->op1.u.constant), (void**)&pce_orig) == SUCCESS &&
+ *pce != *pce_orig)) {
+ do_bind_inherited_class(EX(opline), EG(class_table), EX_T(EX(opline)->extended_value).class_entry, 0 TSRMLS_CC);
+ }
+ EX(opline)++;
+ return ZEND_USER_OPCODE_CONTINUE;
+}
+#endif
+
+static int filename_is_in_cache(char *filename, int filename_len TSRMLS_DC)
+{
+ char *key;
+ int key_length;
+ zend_file_handle handle = {0};
+ zend_persistent_script *persistent_script;
+
+ handle.filename = filename;
+ handle.type = ZEND_HANDLE_FILENAME;
+
+ if (IS_ABSOLUTE_PATH(filename, filename_len)) {
+ persistent_script = zend_accel_hash_find(&ZCSG(hash), filename, filename_len + 1);
+ if (persistent_script) {
+ return !persistent_script->corrupted;
+ }
+ }
+
+ if ((key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC)) != NULL) {
+ persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1);
+ return persistent_script && !persistent_script->corrupted;
+ }
+
+ return 0;
+}
+
+static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval **zfilename;
+
+ if (ZEND_NUM_ARGS() != 1 ||
+ zend_get_parameters_array_ex(1, &zfilename) == FAILURE ||
+ Z_TYPE_PP(zfilename) != IS_STRING ||
+ Z_STRLEN_PP(zfilename) == 0) {
+ return 0;
+ }
+ return filename_is_in_cache(Z_STRVAL_PP(zfilename), Z_STRLEN_PP(zfilename) TSRMLS_CC);
+}
+
+static void accel_file_exists(INTERNAL_FUNCTION_PARAMETERS)
+{
+ if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
+ RETURN_TRUE;
+ } else {
+ orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ }
+}
+
+static void accel_is_file(INTERNAL_FUNCTION_PARAMETERS)
+{
+ if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
+ RETURN_TRUE;
+ } else {
+ orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ }
+}
+
+static void accel_is_readable(INTERNAL_FUNCTION_PARAMETERS)
+{
+ if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
+ RETURN_TRUE;
+ } else {
+ orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ }
+}
+
+static ZEND_MINIT_FUNCTION(zend_accelerator)
+{
+ (void)type; /* keep the compiler happy */
+
+ REGISTER_INI_ENTRIES();
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ zend_set_user_opcode_handler(ZEND_DECLARE_INHERITED_CLASS_DELAYED, ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER);
+#endif
+ return SUCCESS;
+}
+
+void zend_accel_override_file_functions(TSRMLS_D)
+{
+ zend_function *old_function;
+ if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
+ /* override file_exists */
+ if (zend_hash_find(CG(function_table), "file_exists", sizeof("file_exists"), (void **)&old_function) == SUCCESS) {
+ orig_file_exists = old_function->internal_function.handler;
+ old_function->internal_function.handler = accel_file_exists;
+ }
+ if (zend_hash_find(CG(function_table), "is_file", sizeof("is_file"), (void **)&old_function) == SUCCESS) {
+ orig_is_file = old_function->internal_function.handler;
+ old_function->internal_function.handler = accel_is_file;
+ }
+ if (zend_hash_find(CG(function_table), "is_readable", sizeof("is_readable"), (void **)&old_function) == SUCCESS) {
+ orig_is_readable = old_function->internal_function.handler;
+ old_function->internal_function.handler = accel_is_readable;
+ }
+ }
+}
+
+static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)
+{
+ (void)type; /* keep the compiler happy */
+
+ UNREGISTER_INI_ENTRIES();
+ return SUCCESS;
+}
+
+void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
+{
+ php_info_print_table_start();
+
+ if (ZCG(enabled) && accel_startup_ok && (ZCG(counted) || ZCSG(accelerator_enabled))) {
+ php_info_print_table_row(2, "Opcode Caching", "Up and Running");
+ } else {
+ php_info_print_table_row(2, "Opcode Caching", "Disabled");
+ }
+ if (ZCG(enabled) && accel_startup_ok && ZCSG(accelerator_enabled) && ZCG(accel_directives).optimization_level) {
+ php_info_print_table_row(2, "Optimization", "Enabled");
+ } else {
+ php_info_print_table_row(2, "Optimization", "Disabled");
+ }
+ if (ZCG(enabled)) {
+ if (!accel_startup_ok || zps_api_failure_reason) {
+ php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
+ } else {
+ char buf[32];
+ php_info_print_table_row(2, "Startup", "OK");
+ php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(hits));
+ php_info_print_table_row(2, "Cache hits", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
+ php_info_print_table_row(2, "Cache misses", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
+ php_info_print_table_row(2, "Used memory", buf);
+ snprintf(buf, sizeof(buf), "%ld", zend_shared_alloc_get_free_memory());
+ php_info_print_table_row(2, "Free memory", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZSMMG(wasted_shared_memory));
+ php_info_print_table_row(2, "Wasted memory", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_direct_entries);
+ php_info_print_table_row(2, "Cached scripts", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_entries);
+ php_info_print_table_row(2, "Cached keys", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).max_num_entries);
+ php_info_print_table_row(2, "Max keys", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(oom_restarts));
+ php_info_print_table_row(2, "OOM restarts", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(wasted_restarts));
+ php_info_print_table_row(2, "Wasted memory restarts", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(hash_restarts));
+ php_info_print_table_row(2, "Hash keys restarts", buf);
+ snprintf(buf, sizeof(buf), "%ld", ZCSG(manual_restarts));
+ php_info_print_table_row(2, "Manual restarts", buf);
+ }
+ }
+
+ php_info_print_table_end();
+ DISPLAY_INI_ENTRIES();
+}
+
+static zend_module_entry accel_module_entry = {
+ STANDARD_MODULE_HEADER,
+ ACCELERATOR_PRODUCT_NAME,
+ accel_functions,
+ ZEND_MINIT(zend_accelerator),
+ ZEND_MSHUTDOWN(zend_accelerator),
+ NULL,
+ NULL,
+ zend_accel_info,
+ ACCELERATOR_VERSION "FE",
+ STANDARD_MODULE_PROPERTIES
+};
+
+int start_accel_module(void)
+{
+ return zend_startup_module(&accel_module_entry);
+}
+
+/* {{{ proto array accelerator_get_scripts()
+ Get the scripts which are accelerated by ZendAccelerator */
+static zval* accelerator_get_scripts(TSRMLS_D)
+{
+ uint i;
+ zval *return_value,*persistent_script_report;
+ zend_accel_hash_entry *cache_entry;
+ struct tm *ta;
+ struct timeval exec_time;
+ struct timeval fetch_time;
+
+ if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
+ return 0;
+ }
+
+ MAKE_STD_ZVAL(return_value);
+ array_init(return_value);
+ for (i = 0; i<ZCSG(hash).max_num_entries; i++) {
+ for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
+ zend_persistent_script *script;
+ char *str;
+ size_t len;
+
+ if (cache_entry->indirect) continue;
+
+ script = (zend_persistent_script *)cache_entry->data;
+
+ MAKE_STD_ZVAL(persistent_script_report);
+ array_init(persistent_script_report);
+ add_assoc_stringl(persistent_script_report, "full_path", script->full_path, script->full_path_len, 1);
+ add_assoc_long(persistent_script_report, "hits", script->dynamic_members.hits);
+ add_assoc_long(persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption);
+ ta = localtime(&script->dynamic_members.last_used);
+ str = asctime(ta);
+ len = strlen(str);
+ if (len > 0 && str[len - 1] == '\n') len--;
+ add_assoc_stringl(persistent_script_report, "last_used", str, len, 1);
+ add_assoc_long(persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used);
+ if (ZCG(accel_directives).validate_timestamps) {
+ add_assoc_long(persistent_script_report, "timestamp", (long)script->timestamp);
+ }
+ timerclear(&exec_time);
+ timerclear(&fetch_time);
+
+ zend_hash_update(return_value->value.ht, cache_entry->key, cache_entry->key_length, &persistent_script_report, sizeof(zval *), NULL);
+ }
+ }
+ accelerator_shm_read_unlock(TSRMLS_C);
+
+ return return_value;
+}
+
+/* {{{ proto array accelerator_get_status([bool fetch_scripts])
+ Obtain statistics information regarding code acceleration */
+static ZEND_FUNCTION(opcache_get_status)
+{
+ long reqs;
+ zval *memory_usage,*statistics,*scripts;
+ zend_bool fetch_scripts = 1;
+
+ /* keep the compiler happy */
+ (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &fetch_scripts) == FAILURE) {
+ return;
+ }
+
+ if (!accel_startup_ok) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ /* Trivia */
+ add_assoc_bool(return_value, "opcache_enabled", ZCG(enabled) && (ZCG(counted) || ZCSG(accelerator_enabled)));
+ add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
+ add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
+ add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
+
+ /* Memory usage statistics */
+ MAKE_STD_ZVAL(memory_usage);
+ array_init(memory_usage);
+ add_assoc_long(memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
+ add_assoc_long(memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
+ add_assoc_long(memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
+ add_assoc_double(memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
+ add_assoc_zval(return_value, "memory_usage", memory_usage);
+
+ /* Accelerator statistics */
+ MAKE_STD_ZVAL(statistics);
+ array_init(statistics);
+ add_assoc_long(statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
+ add_assoc_long(statistics, "num_cached_keys", ZCSG(hash).num_entries);
+ add_assoc_long(statistics, "max_cached_keys", ZCSG(hash).max_num_entries);
+ add_assoc_long(statistics, "hits", ZCSG(hits));
+ add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time));
+ add_assoc_long(statistics, "oom_restarts", ZCSG(oom_restarts));
+ add_assoc_long(statistics, "wasted_restarts", ZCSG(wasted_restarts));
+ add_assoc_long(statistics, "hash_restarts", ZCSG(hash_restarts));
+ add_assoc_long(statistics, "manual_restarts", ZCSG(manual_restarts));
+ add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
+ add_assoc_long(statistics, "blacklist_misses", ZCSG(blacklist_misses));
+ reqs = ZCSG(hits)+ZCSG(misses);
+ add_assoc_double(statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
+ add_assoc_double(statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
+ add_assoc_zval(return_value, "opcache_statistics", statistics);
+
+ if (fetch_scripts) {
+ /* accelerated scripts */
+ scripts = accelerator_get_scripts(TSRMLS_C);
+ if (scripts) {
+ add_assoc_zval(return_value, "scripts", scripts);
+ }
+ }
+}
+
+static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value TSRMLS_DC)
+{
+ add_next_index_stringl(return_value, p->path, p->path_length, 1);
+ return 0;
+}
+
+/* {{{ proto array accelerator_get_configuration()
+ Obtain configuration information */
+static ZEND_FUNCTION(opcache_get_configuration)
+{
+ zval *directives,*version,*blacklist;
+
+ /* keep the compiler happy */
+ (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if (zend_parse_parameters_none() == FAILURE) {
+ RETURN_FALSE;
+ }
+#endif
+
+ array_init(return_value);
+
+ /* directives */
+ MAKE_STD_ZVAL(directives);
+ array_init(directives);
+ add_assoc_bool(directives, "opcache.enable", ZCG(enabled));
+ add_assoc_bool(directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
+ add_assoc_bool(directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
+ add_assoc_bool(directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
+ add_assoc_bool(directives, "opcache.inherited_hack", ZCG(accel_directives).inherited_hack);
+ add_assoc_bool(directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
+ add_assoc_bool(directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
+
+ add_assoc_long(directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level);
+ add_assoc_long(directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption);
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ add_assoc_long(directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
+#endif
+ add_assoc_long(directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files);
+ add_assoc_double(directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage);
+ add_assoc_long(directives, "opcache.consistency_checks", ZCG(accel_directives).consistency_checks);
+ add_assoc_long(directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout);
+ add_assoc_long(directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq);
+ add_assoc_string(directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model), 1);
+ add_assoc_string(directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename), 1);
+ add_assoc_long(directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size);
+ add_assoc_string(directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log), 1);
+
+ add_assoc_bool(directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
+ add_assoc_bool(directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
+ add_assoc_bool(directives, "opcache.load_comments", ZCG(accel_directives).load_comments);
+ add_assoc_bool(directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown);
+ add_assoc_bool(directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
+ add_assoc_long(directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level);
+
+ add_assoc_zval(return_value, "directives", directives);
+
+ /*version */
+ MAKE_STD_ZVAL(version);
+ array_init(version);
+ add_assoc_string(version, "version", ACCELERATOR_VERSION, 1);
+ add_assoc_string(version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME, 1);
+ add_assoc_zval(return_value, "version", version);
+
+ /* blacklist */
+ MAKE_STD_ZVAL(blacklist);
+ array_init(blacklist);
+ zend_accel_blacklist_apply(&accel_blacklist, (apply_func_arg_t) add_blacklist_path, blacklist TSRMLS_CC);
+ add_assoc_zval(return_value, "blacklist", blacklist);
+}
+
+/* {{{ proto void accelerator_reset()
+ Request that the contents of the opcode cache to be reset */
+static ZEND_FUNCTION(opcache_reset)
+{
+ /* keep the compiler happy */
+ (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if (zend_parse_parameters_none() == FAILURE) {
+ RETURN_FALSE;
+ }
+#endif
+
+ if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
+ RETURN_FALSE;
+ }
+
+ zend_accel_schedule_restart(ACCEL_RESTART_USER TSRMLS_CC);
+ RETURN_TRUE;
+}
diff --git a/ext/opcache/zend_accelerator_module.h b/ext/opcache/zend_accelerator_module.h
new file mode 100644
index 000000000..539b4e85a
--- /dev/null
+++ b/ext/opcache/zend_accelerator_module.h
@@ -0,0 +1,28 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_MODULE_H
+#define ZEND_ACCELERATOR_MODULE_H
+
+int start_accel_module(void);
+void zend_accel_override_file_functions(TSRMLS_D);
+
+#endif /* _ZEND_ACCELERATOR_MODULE_H */
diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c
new file mode 100644
index 000000000..7d5028c4c
--- /dev/null
+++ b/ext/opcache/zend_accelerator_util_funcs.c
@@ -0,0 +1,1007 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend_API.h"
+#include "zend_constants.h"
+#include "zend_accelerator_util_funcs.h"
+#include "zend_persist.h"
+#include "zend_shared_alloc.h"
+
+#define ZEND_PROTECTED_REFCOUNT (1<<30)
+
+static zend_uint zend_accel_refcount = ZEND_PROTECTED_REFCOUNT;
+
+#if SIZEOF_SIZE_T <= SIZEOF_LONG
+/* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
+# define accel_xlat_set(old, new) zend_hash_index_update(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), &(new), sizeof(void*), NULL)
+# define accel_xlat_get(old, new) zend_hash_index_find(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), (void**)&(new))
+#else
+# define accel_xlat_set(old, new) zend_hash_quick_add(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new), sizeof(void*), NULL)
+# define accel_xlat_get(old, new) zend_hash_quick_find(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new))
+#endif
+
+typedef int (*id_function_t)(void *, void *);
+typedef void (*unique_copy_ctor_func_t)(void *pElement);
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+static const Bucket *uninitialized_bucket = NULL;
+#endif
+
+static int zend_prepare_function_for_execution(zend_op_array *op_array);
+static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind);
+
+static void zend_accel_destroy_zend_function(zend_function *function)
+{
+ TSRMLS_FETCH();
+
+ if (function->type == ZEND_USER_FUNCTION) {
+ if (function->op_array.static_variables) {
+
+ efree(function->op_array.static_variables);
+ function->op_array.static_variables = NULL;
+ }
+ }
+
+ destroy_zend_function(function TSRMLS_CC);
+}
+
+static void zend_accel_destroy_zend_class(zend_class_entry **pce)
+{
+ zend_class_entry *ce = *pce;
+
+ ce->function_table.pDestructor = (dtor_func_t) zend_accel_destroy_zend_function;
+ destroy_zend_class(pce);
+}
+
+zend_persistent_script* create_persistent_script(void)
+{
+ zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
+ memset(persistent_script, 0, sizeof(zend_persistent_script));
+
+ zend_hash_init(&persistent_script->function_table, 100, NULL, (dtor_func_t) zend_accel_destroy_zend_function, 0);
+ /* class_table is usually destroyed by free_persistent_script() that
+ * overrides destructor. ZEND_CLASS_DTOR may be used by standard
+ * PHP compiler
+ */
+ zend_hash_init(&persistent_script->class_table, 10, NULL, ZEND_CLASS_DTOR, 0);
+
+ return persistent_script;
+}
+
+void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
+{
+ if (destroy_elements) {
+ persistent_script->function_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_function;
+ persistent_script->class_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_class;
+ } else {
+ persistent_script->function_table.pDestructor = NULL;
+ persistent_script->class_table.pDestructor = NULL;
+ }
+
+ zend_hash_destroy(&persistent_script->function_table);
+ zend_hash_destroy(&persistent_script->class_table);
+
+ if (persistent_script->full_path) {
+ efree(persistent_script->full_path);
+ }
+
+ efree(persistent_script);
+}
+
+static int is_not_internal_function(zend_function *function)
+{
+ return(function->type != ZEND_INTERNAL_FUNCTION);
+}
+
+void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC)
+{
+ dtor_func_t orig_dtor = ht->pDestructor;
+
+ ht->pDestructor = NULL;
+ zend_hash_apply(ht, (apply_func_t) is_not_internal_function TSRMLS_CC);
+ ht->pDestructor = orig_dtor;
+}
+
+static int move_user_function(zend_function *function TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ HashTable *function_table = va_arg(args, HashTable *);
+ (void)num_args; /* keep the compiler happy */
+
+ if (function->type == ZEND_USER_FUNCTION) {
+ zend_hash_quick_update(function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, function, sizeof(zend_function), NULL);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void zend_accel_move_user_functions(HashTable *src, HashTable *dst TSRMLS_DC)
+{
+ dtor_func_t orig_dtor = src->pDestructor;
+
+ src->pDestructor = NULL;
+ zend_hash_apply_with_arguments(src TSRMLS_CC, (apply_func_args_t)move_user_function, 1, dst);
+ src->pDestructor = orig_dtor;
+}
+
+static int copy_internal_function(zend_function *function, HashTable *function_table TSRMLS_DC)
+{
+ if (function->type == ZEND_INTERNAL_FUNCTION) {
+ zend_hash_update(function_table, function->common.function_name, strlen(function->common.function_name) + 1, function, sizeof(zend_function), NULL);
+ }
+ return 0;
+}
+
+void zend_accel_copy_internal_functions(TSRMLS_D)
+{
+ zend_hash_apply_with_argument(CG(function_table), (apply_func_arg_t)copy_internal_function, &ZCG(function_table) TSRMLS_CC);
+ ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
+}
+
+static void zend_destroy_property_info(zend_property_info *property_info)
+{
+ interned_efree((char*)property_info->name);
+ if (property_info->doc_comment) {
+ efree((char*)property_info->doc_comment);
+ }
+}
+
+static inline zval* zend_clone_zval(zval *src, int bind TSRMLS_DC)
+{
+ zval *ret, **ret_ptr = NULL;
+
+ if (!bind) {
+ ALLOC_ZVAL(ret);
+ *ret = *src;
+ INIT_PZVAL(ret);
+ } else if (Z_REFCOUNT_P(src) == 1) {
+ ALLOC_ZVAL(ret);
+ *ret = *src;
+ } else if (accel_xlat_get(src, ret_ptr) != SUCCESS) {
+ ALLOC_ZVAL(ret);
+ *ret = *src;
+ accel_xlat_set(src, ret);
+ } else {
+ return *ret_ptr;
+ }
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
+ switch ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK)) {
+#else
+ if ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
+ switch ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX)) {
+#endif
+ case IS_STRING:
+ case IS_CONSTANT:
+ Z_STRVAL_P(ret) = (char *) interned_estrndup(Z_STRVAL_P(ret), Z_STRLEN_P(ret));
+ break;
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ if (ret->value.ht && ret->value.ht != &EG(symbol_table)) {
+ ALLOC_HASHTABLE(ret->value.ht);
+ zend_hash_clone_zval(ret->value.ht, src->value.ht, 0);
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
+{
+ Bucket *p, *q, **prev;
+ ulong nIndex;
+ zval *ppz;
+ TSRMLS_FETCH();
+
+ ht->nTableSize = source->nTableSize;
+ ht->nTableMask = source->nTableMask;
+ ht->nNumOfElements = source->nNumOfElements;
+ ht->nNextFreeElement = source->nNextFreeElement;
+ ht->pDestructor = ZVAL_PTR_DTOR;
+#if ZEND_DEBUG
+ ht->inconsistent = 0;
+#endif
+ ht->persistent = 0;
+ ht->arBuckets = NULL;
+ ht->pListHead = NULL;
+ ht->pListTail = NULL;
+ ht->pInternalPointer = NULL;
+ ht->nApplyCount = 0;
+ ht->bApplyProtection = 1;
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!ht->nTableMask) {
+ ht->arBuckets = (Bucket**)&uninitialized_bucket;
+ return;
+ }
+#endif
+
+ ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
+
+ prev = &ht->pListHead;
+ p = source->pListHead;
+ while (p) {
+ nIndex = p->h & ht->nTableMask;
+
+ /* Create bucket and initialize key */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!p->nKeyLength) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = NULL;
+ } else if (IS_INTERNED(p->arKey)) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = p->arKey;
+ } else {
+ q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
+ q->arKey = ((char*)q) + sizeof(Bucket);
+ memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
+ }
+#else
+ q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
+ if (p->nKeyLength) {
+ memcpy(q->arKey, p->arKey, p->nKeyLength);
+ }
+#endif
+ q->h = p->h;
+ q->nKeyLength = p->nKeyLength;
+
+ /* Insert into hash collision list */
+ q->pNext = ht->arBuckets[nIndex];
+ q->pLast = NULL;
+ if (q->pNext) {
+ q->pNext->pLast = q;
+ }
+ ht->arBuckets[nIndex] = q;
+
+ /* Insert into global list */
+ q->pListLast = ht->pListTail;
+ ht->pListTail = q;
+ q->pListNext = NULL;
+ *prev = q;
+ prev = &q->pListNext;
+
+ /* Copy data */
+ q->pData = &q->pDataPtr;
+ if (!bind) {
+ ALLOC_ZVAL(ppz);
+ *ppz = *((zval*)p->pDataPtr);
+ INIT_PZVAL(ppz);
+ } else if (Z_REFCOUNT_P((zval*)p->pDataPtr) == 1) {
+ ALLOC_ZVAL(ppz);
+ *ppz = *((zval*)p->pDataPtr);
+ } else if (accel_xlat_get(p->pDataPtr, ppz) != SUCCESS) {
+ ALLOC_ZVAL(ppz);
+ *ppz = *((zval*)p->pDataPtr);
+ accel_xlat_set(p->pDataPtr, ppz);
+ } else {
+ q->pDataPtr = *(void**)ppz;
+ p = p->pListNext;
+ continue;
+ }
+ q->pDataPtr = (void*)ppz;
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
+ switch ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK)) {
+#else
+ if ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
+ switch ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX)) {
+#endif
+ case IS_STRING:
+ case IS_CONSTANT:
+ Z_STRVAL_P(ppz) = (char *) interned_estrndup(Z_STRVAL_P((zval*)p->pDataPtr), Z_STRLEN_P((zval*)p->pDataPtr));
+ break;
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ if (((zval*)p->pDataPtr)->value.ht && ((zval*)p->pDataPtr)->value.ht != &EG(symbol_table)) {
+ ALLOC_HASHTABLE(ppz->value.ht);
+ zend_hash_clone_zval(ppz->value.ht, ((zval*)p->pDataPtr)->value.ht, 0);
+ }
+ break;
+ }
+ }
+
+ p = p->pListNext;
+ }
+ ht->pInternalPointer = ht->pListHead;
+}
+
+static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
+{
+ Bucket *p, *q, **prev;
+ ulong nIndex;
+ zend_class_entry **new_ce;
+ zend_function** new_prototype;
+ zend_op_array *new_entry;
+
+ ht->nTableSize = source->nTableSize;
+ ht->nTableMask = source->nTableMask;
+ ht->nNumOfElements = source->nNumOfElements;
+ ht->nNextFreeElement = source->nNextFreeElement;
+ ht->pDestructor = ZEND_FUNCTION_DTOR;
+#if ZEND_DEBUG
+ ht->inconsistent = 0;
+#endif
+ ht->persistent = 0;
+ ht->pListHead = NULL;
+ ht->pListTail = NULL;
+ ht->pInternalPointer = NULL;
+ ht->nApplyCount = 0;
+ ht->bApplyProtection = 1;
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!ht->nTableMask) {
+ ht->arBuckets = (Bucket**)&uninitialized_bucket;
+ return;
+ }
+#endif
+
+ ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
+
+ prev = &ht->pListHead;
+ p = source->pListHead;
+ while (p) {
+ nIndex = p->h & ht->nTableMask;
+
+ /* Create bucket and initialize key */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!p->nKeyLength) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = NULL;
+ } else if (IS_INTERNED(p->arKey)) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = p->arKey;
+ } else {
+ q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
+ q->arKey = ((char*)q) + sizeof(Bucket);
+ memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
+ }
+#else
+ q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
+ if (p->nKeyLength) {
+ memcpy(q->arKey, p->arKey, p->nKeyLength);
+ }
+#endif
+ q->h = p->h;
+ q->nKeyLength = p->nKeyLength;
+
+ /* Insert into hash collision list */
+ q->pNext = ht->arBuckets[nIndex];
+ q->pLast = NULL;
+ if (q->pNext) {
+ q->pNext->pLast = q;
+ }
+ ht->arBuckets[nIndex] = q;
+
+ /* Insert into global list */
+ q->pListLast = ht->pListTail;
+ ht->pListTail = q;
+ q->pListNext = NULL;
+ *prev = q;
+ prev = &q->pListNext;
+
+ /* Copy data */
+ q->pData = (void *) emalloc(sizeof(zend_function));
+ new_entry = (zend_op_array*)q->pData;
+ *new_entry = *(zend_op_array*)p->pData;
+ q->pDataPtr = NULL;
+
+ /* Copy constructor */
+ /* we use refcount to show that op_array is referenced from several places */
+ if (new_entry->refcount != NULL) {
+ accel_xlat_set(p->pData, new_entry);
+ }
+
+ zend_prepare_function_for_execution(new_entry);
+
+ if (old_ce == new_entry->scope) {
+ new_entry->scope = ce;
+ } else {
+ if (accel_xlat_get(new_entry->scope, new_ce) == SUCCESS) {
+ new_entry->scope = *new_ce;
+ } else {
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s. Please call Zend Support", ce->name, new_entry->function_name);
+ }
+ }
+
+ /* update prototype */
+ if (new_entry->prototype) {
+ if (accel_xlat_get(new_entry->prototype, new_prototype) == SUCCESS) {
+ new_entry->prototype = *new_prototype;
+ } else {
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s. Please call Zend Support", ce->name, new_entry->function_name);
+ }
+ }
+
+ p = p->pListNext;
+ }
+ ht->pInternalPointer = ht->pListHead;
+}
+
+static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
+{
+ Bucket *p, *q, **prev;
+ ulong nIndex;
+ zend_class_entry **new_ce;
+ zend_property_info *prop_info;
+
+ ht->nTableSize = source->nTableSize;
+ ht->nTableMask = source->nTableMask;
+ ht->nNumOfElements = source->nNumOfElements;
+ ht->nNextFreeElement = source->nNextFreeElement;
+ ht->pDestructor = (dtor_func_t) zend_destroy_property_info;
+#if ZEND_DEBUG
+ ht->inconsistent = 0;
+#endif
+ ht->persistent = 0;
+ ht->pListHead = NULL;
+ ht->pListTail = NULL;
+ ht->pInternalPointer = NULL;
+ ht->nApplyCount = 0;
+ ht->bApplyProtection = 1;
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!ht->nTableMask) {
+ ht->arBuckets = (Bucket**)&uninitialized_bucket;
+ return;
+ }
+#endif
+
+ ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
+
+ prev = &ht->pListHead;
+ p = source->pListHead;
+ while (p) {
+ nIndex = p->h & ht->nTableMask;
+
+ /* Create bucket and initialize key */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (!p->nKeyLength) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = NULL;
+ } else if (IS_INTERNED(p->arKey)) {
+ q = (Bucket *) emalloc(sizeof(Bucket));
+ q->arKey = p->arKey;
+ } else {
+ q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
+ q->arKey = ((char*)q) + sizeof(Bucket);
+ memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
+ }
+#else
+ q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
+ if (p->nKeyLength) {
+ memcpy(q->arKey, p->arKey, p->nKeyLength);
+ }
+#endif
+ q->h = p->h;
+ q->nKeyLength = p->nKeyLength;
+
+ /* Insert into hash collision list */
+ q->pNext = ht->arBuckets[nIndex];
+ q->pLast = NULL;
+ if (q->pNext) {
+ q->pNext->pLast = q;
+ }
+ ht->arBuckets[nIndex] = q;
+
+ /* Insert into global list */
+ q->pListLast = ht->pListTail;
+ ht->pListTail = q;
+ q->pListNext = NULL;
+ *prev = q;
+ prev = &q->pListNext;
+
+ /* Copy data */
+ q->pData = (void *) emalloc(sizeof(zend_property_info));
+ prop_info = q->pData;
+ *prop_info = *(zend_property_info*)p->pData;
+ q->pDataPtr = NULL;
+
+ /* Copy constructor */
+ prop_info->name = interned_estrndup(prop_info->name, prop_info->name_length);
+ if (prop_info->doc_comment) {
+ if (ZCG(accel_directives).load_comments) {
+ prop_info->doc_comment = estrndup(prop_info->doc_comment, prop_info->doc_comment_len);
+ } else {
+ prop_info->doc_comment = NULL;
+ }
+ }
+ if (prop_info->ce == old_ce) {
+ prop_info->ce = ce;
+ } else if (accel_xlat_get(prop_info->ce, new_ce) == SUCCESS) {
+ prop_info->ce = *new_ce;
+ } else {
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s, property %s. Please call Zend Support", ce->name, prop_info->name);
+ }
+
+ p = p->pListNext;
+ }
+ ht->pInternalPointer = ht->pListHead;
+}
+
+/* protects reference count, creates copy of statics */
+static int zend_prepare_function_for_execution(zend_op_array *op_array)
+{
+ HashTable *shared_statics = op_array->static_variables;
+
+ /* protect reference count */
+ op_array->refcount = &zend_accel_refcount;
+ (*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
+
+ /* copy statics */
+ if (shared_statics) {
+ ALLOC_HASHTABLE(op_array->static_variables);
+ zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
+ }
+
+ return 0;
+}
+
+#define zend_update_inherited_handler(handler) \
+{ \
+ if (ce->handler != NULL) { \
+ if (accel_xlat_get(ce->handler, new_func) == SUCCESS) { \
+ ce->handler = *new_func; \
+ } else { \
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s. Please call Zend Support", ce->name); \
+ } \
+ } \
+}
+
+/* Protects class' refcount, copies default properties, functions and class name */
+static void zend_class_copy_ctor(zend_class_entry **pce)
+{
+ zend_class_entry *ce = *pce;
+ zend_class_entry *old_ce = ce;
+ zend_class_entry **new_ce;
+ zend_function **new_func;
+ TSRMLS_FETCH();
+
+ *pce = ce = emalloc(sizeof(zend_class_entry));
+ *ce = *old_ce;
+ ce->refcount = 1;
+
+ if (old_ce->refcount != 1) {
+ /* this class is not used as a parent for any other classes */
+ accel_xlat_set(old_ce, ce);
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (old_ce->default_properties_table) {
+ int i;
+
+ ce->default_properties_table = emalloc(sizeof(zval*) * old_ce->default_properties_count);
+ for (i = 0; i < old_ce->default_properties_count; i++) {
+ if (old_ce->default_properties_table[i]) {
+ ce->default_properties_table[i] = zend_clone_zval(old_ce->default_properties_table[i], 0 TSRMLS_CC);
+ } else {
+ ce->default_properties_table[i] = NULL;
+ }
+ }
+ }
+#else
+ zend_hash_clone_zval(&ce->default_properties, &old_ce->default_properties, 0);
+#endif
+
+ zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce TSRMLS_CC);
+
+ /* static members */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (old_ce->default_static_members_table) {
+ int i;
+
+ ce->default_static_members_table = emalloc(sizeof(zval*) * old_ce->default_static_members_count);
+ for (i = 0; i < old_ce->default_static_members_count; i++) {
+ if (old_ce->default_static_members_table[i]) {
+ ce->default_static_members_table[i] = zend_clone_zval(old_ce->default_static_members_table[i], 1 TSRMLS_CC);
+ } else {
+ ce->default_static_members_table[i] = NULL;
+ }
+ }
+ }
+ ce->static_members_table = ce->default_static_members_table;
+#else
+ zend_hash_clone_zval(&ce->default_static_members, &old_ce->default_static_members, 1);
+ ce->static_members = &ce->default_static_members;
+#endif
+
+ /* properties_info */
+ zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce, ce TSRMLS_CC);
+
+ /* constants table */
+ zend_hash_clone_zval(&ce->constants_table, &old_ce->constants_table, 0);
+
+ ce->name = interned_estrndup(ce->name, ce->name_length);
+
+ /* interfaces aren't really implemented, so we create a new table */
+ if (ce->num_interfaces) {
+ ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
+ memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
+ } else {
+ ce->interfaces = NULL;
+ }
+ if (ZEND_CE_DOC_COMMENT(ce)) {
+ if (ZCG(accel_directives).load_comments) {
+ ZEND_CE_DOC_COMMENT(ce) = estrndup(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce));
+ } else {
+ ZEND_CE_DOC_COMMENT(ce) = NULL;
+ }
+ }
+
+ if (ce->parent) {
+ if (accel_xlat_get(ce->parent, new_ce) == SUCCESS) {
+ ce->parent = *new_ce;
+ } else {
+ zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s. Please call Zend Support", ce->name);
+ }
+ }
+
+ zend_update_inherited_handler(constructor);
+ zend_update_inherited_handler(destructor);
+ zend_update_inherited_handler(clone);
+ zend_update_inherited_handler(__get);
+ zend_update_inherited_handler(__set);
+ zend_update_inherited_handler(__call);
+/* 5.1 stuff */
+ zend_update_inherited_handler(serialize_func);
+ zend_update_inherited_handler(unserialize_func);
+ zend_update_inherited_handler(__isset);
+ zend_update_inherited_handler(__unset);
+/* 5.2 stuff */
+ zend_update_inherited_handler(__tostring);
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+/* 5.3 stuff */
+ zend_update_inherited_handler(__callstatic);
+#endif
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+/* 5.4 traits */
+ if (ce->trait_aliases) {
+ zend_trait_alias **trait_aliases;
+ int i = 0;
+
+ while (ce->trait_aliases[i]) {
+ i++;
+ }
+ trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
+ i = 0;
+ while (ce->trait_aliases[i]) {
+ trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
+ memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
+ trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
+ memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
+ if (trait_aliases[i]->trait_method) {
+ if (trait_aliases[i]->trait_method->method_name) {
+ trait_aliases[i]->trait_method->method_name =
+ estrndup(trait_aliases[i]->trait_method->method_name,
+ trait_aliases[i]->trait_method->mname_len);
+ }
+ if (trait_aliases[i]->trait_method->class_name) {
+ trait_aliases[i]->trait_method->class_name =
+ estrndup(trait_aliases[i]->trait_method->class_name,
+ trait_aliases[i]->trait_method->cname_len);
+ }
+ }
+
+ if (trait_aliases[i]->alias) {
+ trait_aliases[i]->alias =
+ estrndup(trait_aliases[i]->alias,
+ trait_aliases[i]->alias_len);
+ }
+ i++;
+ }
+ trait_aliases[i] = NULL;
+ ce->trait_aliases = trait_aliases;
+ }
+
+ if (ce->trait_precedences) {
+ zend_trait_precedence **trait_precedences;
+ int i = 0;
+
+ while (ce->trait_precedences[i]) {
+ i++;
+ }
+ trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
+ i = 0;
+ while (ce->trait_precedences[i]) {
+ trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
+ memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
+ trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
+ memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
+
+ trait_precedences[i]->trait_method->method_name =
+ estrndup(trait_precedences[i]->trait_method->method_name,
+ trait_precedences[i]->trait_method->mname_len);
+ trait_precedences[i]->trait_method->class_name =
+ estrndup(trait_precedences[i]->trait_method->class_name,
+ trait_precedences[i]->trait_method->cname_len);
+
+ if (trait_precedences[i]->exclude_from_classes) {
+ zend_class_entry **exclude_from_classes;
+ int j = 0;
+
+ while (trait_precedences[i]->exclude_from_classes[j]) {
+ j++;
+ }
+ exclude_from_classes = emalloc(sizeof(zend_class_entry*) * (j + 1));
+ j = 0;
+ while (trait_precedences[i]->exclude_from_classes[j]) {
+ exclude_from_classes[j] = (zend_class_entry*)estrndup(
+ (char*)trait_precedences[i]->exclude_from_classes[j],
+ strlen((char*)trait_precedences[i]->exclude_from_classes[j]));
+ j++;
+ }
+ exclude_from_classes[j] = NULL;
+ trait_precedences[i]->exclude_from_classes = exclude_from_classes;
+ }
+ i++;
+ }
+ trait_precedences[i] = NULL;
+ ce->trait_precedences = trait_precedences;
+ }
+#endif
+}
+
+static int zend_hash_unique_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor, uint size, int ignore_dups, void **fail_data, void **conflict_data)
+{
+ Bucket *p;
+ void *t;
+
+ p = source->pListHead;
+ while (p) {
+ if (p->nKeyLength > 0) {
+ if (zend_hash_quick_add(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t) == SUCCESS) {
+ if (pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ } else {
+ if (p->nKeyLength > 0 && p->arKey[0] == 0) {
+ /* Mangled key, ignore and wait for runtime */
+ } else if (!ignore_dups && zend_hash_quick_find(target, p->arKey, p->nKeyLength, p->h, &t) == SUCCESS) {
+ *fail_data = p->pData;
+ *conflict_data = t;
+ return FAILURE;
+ }
+ }
+ } else {
+ if (!zend_hash_index_exists(target, p->h) && zend_hash_index_update(target, p->h, p->pData, size, &t) == SUCCESS) {
+ if (pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ } else if (!ignore_dups && zend_hash_index_find(target,p->h, &t) == SUCCESS) {
+ *fail_data = p->pData;
+ *conflict_data = t;
+ return FAILURE;
+ }
+ }
+ p = p->pListNext;
+ }
+ target->pInternalPointer = target->pListHead;
+
+ return SUCCESS;
+}
+
+static void zend_accel_function_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
+{
+ zend_function *function1, *function2;
+ TSRMLS_FETCH();
+
+ if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_function), 0, (void**)&function1, (void**)&function2) != SUCCESS) {
+ CG(in_compilation) = 1;
+ zend_set_compiled_filename(function1->op_array.filename TSRMLS_CC);
+ CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
+ if (function2->type == ZEND_USER_FUNCTION
+ && function2->op_array.last > 0) {
+ zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
+ function1->common.function_name,
+ function2->op_array.filename,
+ (int)function2->op_array.opcodes[0].lineno);
+ } else {
+ zend_error(E_ERROR, "Cannot redeclare %s()", function1->common.function_name);
+ }
+ }
+}
+
+static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor TSRMLS_DC)
+{
+ zend_class_entry **pce1, **pce2;
+
+ if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_class_entry*), ZCG(accel_directives).ignore_dups, (void**)&pce1, (void**)&pce2) != SUCCESS) {
+ CG(in_compilation) = 1;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ zend_set_compiled_filename((*pce1)->info.user.filename TSRMLS_CC);
+ CG(zend_lineno) = (*pce1)->info.user.line_start;
+#else
+ zend_set_compiled_filename((*pce1)->filename TSRMLS_CC);
+ CG(zend_lineno) = (*pce1)->line_start;
+#endif
+ zend_error(E_ERROR, "Cannot redeclare class %s", (*pce1)->name);
+ }
+}
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+static void zend_do_delayed_early_binding(zend_op_array *op_array, zend_uint early_binding TSRMLS_DC)
+{
+ zend_uint opline_num = early_binding;
+
+ if ((int)opline_num != -1) {
+ zend_bool orig_in_compilation = CG(in_compilation);
+ char *orig_compiled_filename = zend_set_compiled_filename(op_array->filename TSRMLS_CC);
+ zend_class_entry **pce;
+
+ CG(in_compilation) = 1;
+ while ((int)opline_num != -1) {
+ if (zend_lookup_class(Z_STRVAL(op_array->opcodes[opline_num - 1].op2.u.constant), Z_STRLEN(op_array->opcodes[opline_num - 1].op2.u.constant), &pce TSRMLS_CC) == SUCCESS) {
+ do_bind_inherited_class(&op_array->opcodes[opline_num], EG(class_table), *pce, 1 TSRMLS_CC);
+ }
+ opline_num = op_array->opcodes[opline_num].result.u.opline_num;
+ }
+ zend_restore_compiled_filename(orig_compiled_filename);
+ CG(in_compilation) = orig_in_compilation;
+ }
+}
+#endif
+
+zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory TSRMLS_DC)
+{
+ zend_op_array *op_array;
+
+ op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
+ *op_array = persistent_script->main_op_array;
+
+ if (from_shared_memory) {
+ /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
+ if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
+ zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
+ zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, (unique_copy_ctor_func_t) zend_class_copy_ctor TSRMLS_CC);
+ zend_hash_destroy(&ZCG(bind_hash));
+ }
+ /* we must first to copy all classes and then prepare functions, since functions may try to bind
+ classes - which depend on pre-bind class entries existant in the class table */
+ if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
+ zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, (unique_copy_ctor_func_t)zend_prepare_function_for_execution);
+ }
+
+ zend_prepare_function_for_execution(op_array);
+
+ /* Register __COMPILER_HALT_OFFSET__ constant */
+ if (persistent_script->compiler_halt_offset != 0 &&
+ persistent_script->full_path) {
+ char *name, *cfilename;
+ char haltoff[] = "__COMPILER_HALT_OFFSET__";
+ int len, clen;
+
+ cfilename = persistent_script->full_path;
+ clen = strlen(cfilename);
+ zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
+ if (!zend_hash_exists(EG(zend_constants), name, len + 1)) {
+ zend_register_long_constant(name, len + 1, persistent_script->compiler_halt_offset, CONST_CS, 0 TSRMLS_CC);
+ }
+ efree(name);
+ }
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ if ((int)persistent_script->early_binding != -1) {
+ zend_do_delayed_early_binding(op_array, persistent_script->early_binding TSRMLS_CC);
+ }
+#endif
+
+ } else /* if (!from_shared_memory) */ {
+ if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
+ zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, NULL);
+ }
+ if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
+ zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, NULL TSRMLS_CC);
+ }
+ free_persistent_script(persistent_script, 0); /* free only hashes */
+ }
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if (op_array->early_binding != (zend_uint)-1) {
+ char *orig_compiled_filename = CG(compiled_filename);
+ CG(compiled_filename) = persistent_script->full_path;
+ zend_do_delayed_early_binding(op_array TSRMLS_CC);
+ CG(compiled_filename) = orig_compiled_filename;
+ }
+#endif
+
+ return op_array;
+}
+
+/*
+ * zend_adler32() is based on zlib implementation
+ * Computes the Adler-32 checksum of a data stream
+ *
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+ *
+ * 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.
+ *
+ */
+
+#define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
+#define ADLER32_NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define ADLER32_DO1(buf) {s1 += *(buf); s2 += s1;}
+#define ADLER32_DO2(buf, i) ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
+#define ADLER32_DO4(buf, i) ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
+#define ADLER32_DO8(buf, i) ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
+#define ADLER32_DO16(buf) ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
+
+unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len)
+{
+ unsigned int s1 = checksum & 0xffff;
+ unsigned int s2 = (checksum >> 16) & 0xffff;
+ signed char *end;
+
+ while (len >= ADLER32_NMAX) {
+ len -= ADLER32_NMAX;
+ end = buf + ADLER32_NMAX;
+ do {
+ ADLER32_DO16(buf);
+ buf += 16;
+ } while (buf != end);
+ s1 %= ADLER32_BASE;
+ s2 %= ADLER32_BASE;
+ }
+
+ if (len) {
+ if (len >= 16) {
+ end = buf + (len & 0xfff0);
+ len &= 0xf;
+ do {
+ ADLER32_DO16(buf);
+ buf += 16;
+ } while (buf != end);
+ }
+ if (len) {
+ end = buf + len;
+ do {
+ ADLER32_DO1(buf);
+ buf++;
+ } while (buf != end);
+ }
+ s1 %= ADLER32_BASE;
+ s2 %= ADLER32_BASE;
+ }
+
+ return (s2 << 16) | s1;
+}
diff --git a/ext/opcache/zend_accelerator_util_funcs.h b/ext/opcache/zend_accelerator_util_funcs.h
new file mode 100644
index 000000000..a926145c9
--- /dev/null
+++ b/ext/opcache/zend_accelerator_util_funcs.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ACCELERATOR_UTIL_FUNCS_H
+#define ZEND_ACCELERATOR_UTIL_FUNCS_H
+
+#include "zend.h"
+#include "ZendAccelerator.h"
+
+void zend_accel_copy_internal_functions(TSRMLS_D);
+
+zend_persistent_script* create_persistent_script(void);
+void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements);
+
+void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC);
+void zend_accel_move_user_functions(HashTable *str, HashTable *dst TSRMLS_DC);
+
+zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory TSRMLS_DC);
+
+#define ADLER32_INIT 1 /* initial Adler-32 value */
+
+unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len);
+
+#endif /* ZEND_ACCELERATOR_UTIL_FUNCS_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
new file mode 100644
index 000000000..0bffae4d0
--- /dev/null
+++ b/ext/opcache/zend_persist.c
@@ -0,0 +1,680 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "ZendAccelerator.h"
+#include "zend_persist.h"
+#include "zend_extensions.h"
+#include "zend_shared_alloc.h"
+#include "zend_vm.h"
+#include "zend_constants.h"
+#include "zend_operators.h"
+
+#define zend_accel_store(p, size) \
+ (p = _zend_shared_memdup((void*)p, size, 1 TSRMLS_CC))
+#define zend_accel_memdup(p, size) \
+ _zend_shared_memdup((void*)p, size, 0 TSRMLS_CC)
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+# define zend_accel_memdup_interned_string(str, len) \
+ IS_INTERNED(str) ? str : zend_accel_memdup(str, len)
+
+# define zend_accel_store_interned_string(str, len) do { \
+ if (!IS_INTERNED(str)) { zend_accel_store(str, len); } \
+ } while (0)
+#else
+# define zend_accel_memdup_interned_string(str, len) \
+ zend_accel_memdup(str, len)
+
+# define zend_accel_store_interned_string(str, len) \
+ zend_accel_store(str, len)
+#endif
+
+typedef void (*zend_persist_func_t)(void * TSRMLS_DC);
+
+static void zend_persist_zval_ptr(zval **zp TSRMLS_DC);
+
+static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC)
+{
+ Bucket *p = ht->pListHead;
+ uint i;
+
+ while (p) {
+ Bucket *q = p;
+
+ /* persist bucket and key */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ p = zend_accel_memdup(p, sizeof(Bucket));
+ if (p->nKeyLength) {
+ p->arKey = zend_accel_memdup_interned_string(p->arKey, p->nKeyLength);
+ }
+#else
+ p = zend_accel_memdup(p, sizeof(Bucket) - 1 + p->nKeyLength);
+#endif
+
+ /* persist data pointer in bucket */
+ if (!p->pDataPtr) {
+ zend_accel_store(p->pData, el_size);
+ } else {
+ /* Update p->pData to point to the new p->pDataPtr address, after the bucket relocation */
+ p->pData = &p->pDataPtr;
+ }
+
+ /* persist the data itself */
+ if (pPersistElement) {
+ pPersistElement(p->pData TSRMLS_CC);
+ }
+
+ /* update linked lists */
+ if (p->pLast) {
+ p->pLast->pNext = p;
+ }
+ if (p->pNext) {
+ p->pNext->pLast = p;
+ }
+ if (p->pListLast) {
+ p->pListLast->pListNext = p;
+ }
+ if (p->pListNext) {
+ p->pListNext->pListLast = p;
+ }
+
+ p = p->pListNext;
+
+ /* delete the old non-persistent bucket */
+ efree(q);
+ }
+
+ /* update linked lists */
+ if (ht->pListHead) {
+ ht->pListHead = zend_shared_alloc_get_xlat_entry(ht->pListHead);
+ }
+ if (ht->pListTail) {
+ ht->pListTail = zend_shared_alloc_get_xlat_entry(ht->pListTail);
+ }
+ if (ht->pInternalPointer) {
+ ht->pInternalPointer = zend_shared_alloc_get_xlat_entry(ht->pInternalPointer);
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ /* Check if HastTable is initialized */
+ if (ht->nTableMask) {
+#endif
+ if (ht->nNumOfElements) {
+ /* update hash table */
+ for (i = 0; i < ht->nTableSize; i++) {
+ if (ht->arBuckets[i]) {
+ ht->arBuckets[i] = zend_shared_alloc_get_xlat_entry(ht->arBuckets[i]);
+ }
+ }
+ }
+ zend_accel_store(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize);
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ } else {
+ ht->arBuckets = NULL;
+ }
+#endif
+}
+
+static void zend_persist_zval(zval *z TSRMLS_DC)
+{
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ switch (z->type & IS_CONSTANT_TYPE_MASK) {
+#else
+ switch (z->type & ~IS_CONSTANT_INDEX) {
+#endif
+ case IS_STRING:
+ case IS_CONSTANT:
+ zend_accel_store_interned_string(z->value.str.val, z->value.str.len + 1);
+ break;
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ zend_accel_store(z->value.ht, sizeof(HashTable));
+ zend_hash_persist(z->value.ht, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
+ break;
+ }
+}
+
+static void zend_persist_zval_ptr(zval **zp TSRMLS_DC)
+{
+ zval *new_ptr = zend_shared_alloc_get_xlat_entry(*zp);
+
+ if (new_ptr) {
+ *zp = new_ptr;
+ } else {
+ /* Attempt to store only if we didn't store this zval_ptr yet */
+ zend_accel_store(*zp, sizeof(zval));
+ zend_persist_zval(*zp TSRMLS_CC);
+ }
+}
+
+static void zend_protect_zval(zval *z TSRMLS_DC)
+{
+ PZ_SET_ISREF_P(z);
+ PZ_SET_REFCOUNT_P(z, 2);
+}
+
+static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script TSRMLS_DC)
+{
+ zend_op *persist_ptr;
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ int has_jmp = 0;
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ zend_literal *orig_literals = NULL;
+#endif
+
+ if (op_array->type != ZEND_USER_FUNCTION) {
+ return;
+ }
+
+#if ZEND_EXTENSION_API_NO <= PHP_5_3_X_API_NO
+ op_array->size = op_array->last;
+#endif
+
+ if (--(*op_array->refcount) == 0) {
+ efree(op_array->refcount);
+ }
+ op_array->refcount = NULL;
+
+ if (op_array->filename) {
+ /* do not free! PHP has centralized filename storage, compiler will free it */
+ op_array->filename = zend_accel_memdup(op_array->filename, strlen(op_array->filename) + 1);
+ }
+
+ if (main_persistent_script) {
+ zend_bool orig_in_execution = EG(in_execution);
+ zend_op_array *orig_op_array = EG(active_op_array);
+ zval offset;
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ main_persistent_script->early_binding = -1;
+#endif
+ EG(in_execution) = 1;
+ EG(active_op_array) = op_array;
+ if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) {
+ main_persistent_script->compiler_halt_offset = Z_LVAL(offset);
+ }
+ EG(active_op_array) = orig_op_array;
+ EG(in_execution) = orig_in_execution;
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (op_array->literals) {
+ orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
+ if (orig_literals) {
+ op_array->literals = orig_literals;
+ } else {
+ zend_literal *p = zend_accel_memdup(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
+ zend_literal *end = p + op_array->last_literal;
+ orig_literals = op_array->literals;
+ op_array->literals = p;
+ while (p < end) {
+ zend_persist_zval(&p->constant TSRMLS_CC);
+ zend_protect_zval(&p->constant TSRMLS_CC);
+ p++;
+ }
+ efree(orig_literals);
+ }
+ }
+#endif
+
+ if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes))) {
+ op_array->opcodes = persist_ptr;
+ } else {
+ zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last);
+ zend_op *opline = new_opcodes;
+ zend_op *end = new_opcodes + op_array->last;
+ int offset = 0;
+
+ for (; opline < end ; opline++, offset++) {
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
+#else
+ zend_persist_zval(&opline->op1.u.constant TSRMLS_CC);
+ zend_protect_zval(&opline->op1.u.constant TSRMLS_CC);
+#endif
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
+#else
+ zend_persist_zval(&opline->op2.u.constant TSRMLS_CC);
+ zend_protect_zval(&opline->op2.u.constant TSRMLS_CC);
+#endif
+ }
+
+#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
+ switch (opline->opcode) {
+ case ZEND_JMP:
+ has_jmp = 1;
+ if (ZEND_DONE_PASS_TWO(op_array)) {
+ ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes];
+ }
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ has_jmp = 1;
+ if (ZEND_DONE_PASS_TWO(op_array)) {
+ ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
+ }
+ break;
+ case ZEND_JMPZNZ:
+ case ZEND_BRK:
+ case ZEND_CONT:
+ has_jmp = 1;
+ break;
+ case ZEND_DECLARE_INHERITED_CLASS:
+ if (main_persistent_script && ZCG(accel_directives).inherited_hack) {
+ if (!has_jmp &&
+ ((opline + 2) >= end ||
+ (opline + 1)->opcode != ZEND_FETCH_CLASS ||
+ (opline + 2)->opcode != ZEND_ADD_INTERFACE)) {
+
+ zend_uint *opline_num = &main_persistent_script->early_binding;
+
+ while ((int)*opline_num != -1) {
+ opline_num = &new_opcodes[*opline_num].result.u.opline_num;
+ }
+ *opline_num = opline - new_opcodes;
+ opline->result.op_type = IS_UNUSED;
+ opline->result.u.opline_num = -1;
+ opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
+ ZEND_VM_SET_OPCODE_HANDLER(opline);
+ }
+ break;
+ }
+ }
+
+#else /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */
+
+ if (ZEND_DONE_PASS_TWO(op_array)) {
+ /* fix jumps to point to new array */
+ switch (opline->opcode) {
+ case ZEND_JMP:
+ case ZEND_GOTO:
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+#endif
+ ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes];
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
+ break;
+ }
+ }
+#endif /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */
+ }
+
+ efree(op_array->opcodes);
+ op_array->opcodes = new_opcodes;
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (op_array->run_time_cache) {
+ efree(op_array->run_time_cache);
+ op_array->run_time_cache = NULL;
+ }
+#endif
+ }
+
+ if (op_array->function_name) {
+ char *new_name;
+ if ((new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name))) {
+ op_array->function_name = new_name;
+ } else {
+ zend_accel_store(op_array->function_name, strlen(op_array->function_name) + 1);
+ }
+ }
+
+ if (op_array->arg_info) {
+ zend_arg_info *new_ptr;
+ if ((new_ptr = zend_shared_alloc_get_xlat_entry(op_array->arg_info))) {
+ op_array->arg_info = new_ptr;
+ } else {
+ zend_uint i;
+
+ zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
+ for (i = 0; i < op_array->num_args; i++) {
+ if (op_array->arg_info[i].name) {
+ zend_accel_store_interned_string(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
+ }
+ if (op_array->arg_info[i].class_name) {
+ zend_accel_store_interned_string(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
+ }
+ }
+ }
+ }
+
+ if (op_array->brk_cont_array) {
+ zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
+ }
+
+ if (op_array->static_variables) {
+ zend_hash_persist(op_array->static_variables, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
+ zend_accel_store(op_array->static_variables, sizeof(HashTable));
+ }
+
+ if (op_array->scope) {
+ op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
+ }
+
+ if (op_array->doc_comment) {
+ if (ZCG(accel_directives).save_comments) {
+ zend_accel_store(op_array->doc_comment, op_array->doc_comment_len + 1);
+ } else {
+ if (!zend_shared_alloc_get_xlat_entry(op_array->doc_comment)) {
+ zend_shared_alloc_register_xlat_entry(op_array->doc_comment, op_array->doc_comment);
+ efree((char*)op_array->doc_comment);
+ }
+ op_array->doc_comment = NULL;
+ op_array->doc_comment_len = 0;
+ }
+ }
+
+ if (op_array->try_catch_array) {
+ zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
+ }
+
+ if (op_array->vars) {
+ if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars))) {
+ op_array->vars = (zend_compiled_variable*)persist_ptr;
+ } else {
+ int i;
+ zend_accel_store(op_array->vars, sizeof(zend_compiled_variable) * op_array->last_var);
+ for (i = 0; i < op_array->last_var; i++) {
+ zend_accel_store_interned_string(op_array->vars[i].name, op_array->vars[i].name_len + 1);
+ }
+ }
+ }
+
+ /* "prototype" may be undefined if "scope" isn't set */
+ if (op_array->scope && op_array->prototype) {
+ if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
+ op_array->prototype = (union _zend_function*)persist_ptr;
+ /* we use refcount to show that op_array is referenced from several places */
+ op_array->prototype->op_array.refcount++;
+ }
+ } else {
+ op_array->prototype = NULL;
+ }
+}
+
+static void zend_persist_op_array(zend_op_array *op_array TSRMLS_DC)
+{
+ zend_persist_op_array_ex(op_array, NULL TSRMLS_CC);
+}
+
+static void zend_persist_property_info(zend_property_info *prop TSRMLS_DC)
+{
+ zend_accel_store_interned_string(prop->name, prop->name_length + 1);
+ if (prop->doc_comment) {
+ if (ZCG(accel_directives).save_comments) {
+ zend_accel_store(prop->doc_comment, prop->doc_comment_len + 1);
+ } else {
+ if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
+ zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
+ efree((char*)prop->doc_comment);
+ }
+ prop->doc_comment = NULL;
+ prop->doc_comment_len = 0;
+ }
+ }
+}
+
+static void zend_persist_class_entry(zend_class_entry **pce TSRMLS_DC)
+{
+ zend_class_entry *ce = *pce;
+
+ if (ce->type == ZEND_USER_CLASS) {
+ *pce = zend_accel_store(ce, sizeof(zend_class_entry));
+ zend_accel_store_interned_string(ce->name, ce->name_length + 1);
+ zend_hash_persist(&ce->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC);
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ce->default_properties_table) {
+ int i;
+
+ zend_accel_store(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count);
+ for (i = 0; i < ce->default_properties_count; i++) {
+ if (ce->default_properties_table[i]) {
+ zend_persist_zval_ptr(&ce->default_properties_table[i] TSRMLS_CC);
+ }
+ }
+ }
+ if (ce->default_static_members_table) {
+ int i;
+
+ zend_accel_store(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count);
+ for (i = 0; i < ce->default_static_members_count; i++) {
+ if (ce->default_static_members_table[i]) {
+ zend_persist_zval_ptr(&ce->default_static_members_table[i] TSRMLS_CC);
+ }
+ }
+ }
+ ce->static_members_table = NULL;
+#else
+ zend_hash_persist(&ce->default_properties, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
+ zend_hash_persist(&ce->default_static_members, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
+ ce->static_members = NULL;
+#endif
+ zend_hash_persist(&ce->constants_table, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
+
+ if (ZEND_CE_FILENAME(ce)) {
+ /* do not free! PHP has centralized filename storage, compiler will free it */
+ ZEND_CE_FILENAME(ce) = zend_accel_memdup(ZEND_CE_FILENAME(ce), strlen(ZEND_CE_FILENAME(ce)) + 1);
+ }
+ if (ZEND_CE_DOC_COMMENT(ce)) {
+ if (ZCG(accel_directives).save_comments) {
+ zend_accel_store(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce) + 1);
+ } else {
+ if (!zend_shared_alloc_get_xlat_entry(ZEND_CE_DOC_COMMENT(ce))) {
+ zend_shared_alloc_register_xlat_entry(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT(ce));
+ efree((char*)ZEND_CE_DOC_COMMENT(ce));
+ }
+ ZEND_CE_DOC_COMMENT(ce) = NULL;
+ ZEND_CE_DOC_COMMENT_LEN(ce) = 0;
+ }
+ }
+ zend_hash_persist(&ce->properties_info, (zend_persist_func_t) zend_persist_property_info, sizeof(zend_property_info) TSRMLS_CC);
+ if (ce->num_interfaces && ce->interfaces) {
+ efree(ce->interfaces);
+ }
+ ce->interfaces = NULL; /* will be filled in on fetch */
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ce->num_traits && ce->traits) {
+ efree(ce->traits);
+ }
+ ce->traits = NULL;
+
+ if (ce->trait_aliases) {
+ int i = 0;
+ while (ce->trait_aliases[i]) {
+ if (ce->trait_aliases[i]->trait_method) {
+ if (ce->trait_aliases[i]->trait_method->method_name) {
+ zend_accel_store(ce->trait_aliases[i]->trait_method->method_name,
+ ce->trait_aliases[i]->trait_method->mname_len + 1);
+ }
+ if (ce->trait_aliases[i]->trait_method->class_name) {
+ zend_accel_store(ce->trait_aliases[i]->trait_method->class_name,
+ ce->trait_aliases[i]->trait_method->cname_len + 1);
+ }
+ ce->trait_aliases[i]->trait_method->ce = NULL;
+ zend_accel_store(ce->trait_aliases[i]->trait_method,
+ sizeof(zend_trait_method_reference));
+ }
+
+ if (ce->trait_aliases[i]->alias) {
+ zend_accel_store(ce->trait_aliases[i]->alias,
+ ce->trait_aliases[i]->alias_len + 1);
+ }
+
+#if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO
+ ce->trait_aliases[i]->function = NULL;
+#endif
+ zend_accel_store(ce->trait_aliases[i], sizeof(zend_trait_alias));
+ i++;
+ }
+
+ zend_accel_store(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
+ }
+
+ if (ce->trait_precedences) {
+ int i = 0;
+
+ while (ce->trait_precedences[i]) {
+ zend_accel_store(ce->trait_precedences[i]->trait_method->method_name,
+ ce->trait_precedences[i]->trait_method->mname_len + 1);
+ zend_accel_store(ce->trait_precedences[i]->trait_method->class_name,
+ ce->trait_precedences[i]->trait_method->cname_len + 1);
+ ce->trait_precedences[i]->trait_method->ce = NULL;
+ zend_accel_store(ce->trait_precedences[i]->trait_method,
+ sizeof(zend_trait_method_reference));
+
+ if (ce->trait_precedences[i]->exclude_from_classes) {
+ int j = 0;
+
+ while (ce->trait_precedences[i]->exclude_from_classes[j]) {
+ zend_accel_store(ce->trait_precedences[i]->exclude_from_classes[j],
+ strlen((char*)ce->trait_precedences[i]->exclude_from_classes[j]) + 1);
+ j++;
+ }
+ zend_accel_store(ce->trait_precedences[i]->exclude_from_classes,
+ sizeof(zend_class_entry*) * (j + 1));
+ }
+
+#if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO
+ ce->trait_precedences[i]->function = NULL;
+#endif
+ zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence));
+ i++;
+ }
+ zend_accel_store(
+ ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
+ }
+#endif
+ }
+}
+
+static int zend_update_property_info_ce(zend_property_info *prop TSRMLS_DC)
+{
+ prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
+ return 0;
+}
+
+static int zend_update_parent_ce(zend_class_entry **pce TSRMLS_DC)
+{
+ zend_class_entry *ce = *pce;
+
+ if (ce->parent) {
+ ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
+ /* We use refcount to show if the class is used as a parent */
+ ce->parent->refcount++;
+ }
+
+ /* update methods */
+ if (ce->constructor) {
+ ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
+ /* we use refcount to show that op_array is referenced from several places */
+ ce->constructor->op_array.refcount++;
+ }
+ if (ce->destructor) {
+ ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
+ ce->destructor->op_array.refcount++;
+ }
+ if (ce->clone) {
+ ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
+ ce->clone->op_array.refcount++;
+ }
+ if (ce->__get) {
+ ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
+ ce->__get->op_array.refcount++;
+ }
+ if (ce->__set) {
+ ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
+ ce->__set->op_array.refcount++;
+ }
+ if (ce->__call) {
+ ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
+ ce->__call->op_array.refcount++;
+ }
+ if (ce->serialize_func) {
+ ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
+ ce->serialize_func->op_array.refcount++;
+ }
+ if (ce->unserialize_func) {
+ ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
+ ce->unserialize_func->op_array.refcount++;
+ }
+ if (ce->__isset) {
+ ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
+ ce->__isset->op_array.refcount++;
+ }
+ if (ce->__unset) {
+ ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
+ ce->__unset->op_array.refcount++;
+ }
+ if (ce->__tostring) {
+ ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
+ ce->__tostring->op_array.refcount++;
+ }
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ if (ce->__callstatic) {
+ ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
+ ce->__callstatic->op_array.refcount++;
+ }
+#endif
+ zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce TSRMLS_CC);
+ return 0;
+}
+
+static void zend_accel_persist_class_table(HashTable *class_table TSRMLS_DC)
+{
+ zend_hash_persist(class_table, (zend_persist_func_t) zend_persist_class_entry, sizeof(zend_class_entry*) TSRMLS_CC);
+ zend_hash_apply(class_table, (apply_func_t) zend_update_parent_ce TSRMLS_CC);
+}
+
+zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length TSRMLS_DC)
+{
+ zend_shared_alloc_clear_xlat_table();
+ zend_hash_persist(&script->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC);
+ zend_accel_persist_class_table(&script->class_table TSRMLS_CC);
+ zend_persist_op_array_ex(&script->main_op_array, script TSRMLS_CC);
+ *key = zend_accel_memdup(*key, key_length + 1);
+ zend_accel_store(script->full_path, script->full_path_len + 1);
+ zend_accel_store(script, sizeof(zend_persistent_script));
+
+ return script;
+}
+
+int zend_accel_script_persistable(zend_persistent_script *script)
+{
+ return 1;
+}
diff --git a/ext/opcache/zend_persist.h b/ext/opcache/zend_persist.h
new file mode 100644
index 000000000..cf3fb73cd
--- /dev/null
+++ b/ext/opcache/zend_persist.h
@@ -0,0 +1,29 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_PERSIST_H
+#define ZEND_PERSIST_H
+
+int zend_accel_script_persistable(zend_persistent_script *script);
+uint zend_accel_script_persist_calc(zend_persistent_script *script, char *key, unsigned int key_length TSRMLS_DC);
+zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length TSRMLS_DC);
+
+#endif /* ZEND_PERSIST_H */
diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c
new file mode 100644
index 000000000..18af756f6
--- /dev/null
+++ b/ext/opcache/zend_persist_calc.c
@@ -0,0 +1,343 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "ZendAccelerator.h"
+#include "zend_persist.h"
+#include "zend_extensions.h"
+#include "zend_shared_alloc.h"
+#include "zend_operators.h"
+
+#define START_SIZE() uint memory_used = 0
+#define ADD_DUP_SIZE(m,s) memory_used += zend_shared_memdup_size((void*)m, s)
+#define ADD_SIZE(m) memory_used += ZEND_ALIGNED_SIZE(m)
+#define RETURN_SIZE() return memory_used
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+# define ADD_INTERNED_STRING(str, len) do { \
+ const char *tmp = accel_new_interned_string((str), (len), !IS_INTERNED((str)) TSRMLS_CC); \
+ if (tmp != (str)) { \
+ (str) = (char*)tmp; \
+ } else { \
+ ADD_DUP_SIZE((str), (len)); \
+ } \
+ } while (0)
+#else
+# define ADD_INTERNED_STRING(str, len) ADD_DUP_SIZE((str), (len))
+#endif
+
+static uint zend_persist_zval_ptr_calc(zval **zp TSRMLS_DC);
+
+static uint zend_hash_persist_calc(HashTable *ht, int (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC)
+{
+ Bucket *p = ht->pListHead;
+ START_SIZE();
+
+ while (p) {
+ /* persist bucket and key */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ ADD_DUP_SIZE(p, sizeof(Bucket));
+ if (p->nKeyLength) {
+ const char *tmp = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
+ if (tmp != p->arKey) {
+ p->arKey = tmp;
+ } else {
+ ADD_DUP_SIZE(p->arKey, p->nKeyLength);
+ }
+ }
+#else
+ ADD_DUP_SIZE(p, sizeof(Bucket) - 1 + p->nKeyLength);
+#endif
+
+ /* persist data pointer in bucket */
+ if (!p->pDataPtr) {
+ ADD_DUP_SIZE(p->pData, el_size);
+ }
+
+ /* persist the data itself */
+ if (pPersistElement) {
+ ADD_SIZE(pPersistElement(p->pData TSRMLS_CC));
+ }
+
+ p = p->pListNext;
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ht->nTableMask) {
+ ADD_DUP_SIZE(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize);
+ }
+#else
+ ADD_DUP_SIZE(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize);
+#endif
+
+ RETURN_SIZE();
+}
+
+static uint zend_persist_zval_calc(zval *z TSRMLS_DC)
+{
+ START_SIZE();
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+ switch (z->type & IS_CONSTANT_TYPE_MASK) {
+#else
+ switch (z->type & ~IS_CONSTANT_INDEX) {
+#endif
+ case IS_STRING:
+ case IS_CONSTANT:
+ ADD_INTERNED_STRING(Z_STRVAL_P(z), Z_STRLEN_P(z) + 1);
+ break;
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ ADD_DUP_SIZE(z->value.ht, sizeof(HashTable));
+ ADD_SIZE(zend_hash_persist_calc(z->value.ht, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC));
+ break;
+ }
+ RETURN_SIZE();
+}
+
+static uint zend_persist_zval_ptr_calc(zval **zp TSRMLS_DC)
+{
+ START_SIZE();
+ zval *new_ptr = zend_shared_alloc_get_xlat_entry(*zp);
+
+ if (!new_ptr) {
+ ADD_DUP_SIZE(*zp, sizeof(zval));
+ ADD_SIZE(zend_persist_zval_calc(*zp TSRMLS_CC));
+ }
+ RETURN_SIZE();
+}
+
+static uint zend_persist_op_array_calc(zend_op_array *op_array TSRMLS_DC)
+{
+ START_SIZE();
+
+ if (op_array->type != ZEND_USER_FUNCTION) {
+ return 0;
+ }
+
+ if (op_array->filename) {
+ ADD_DUP_SIZE(op_array->filename, strlen(op_array->filename) + 1);
+ }
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (op_array->literals && !zend_shared_alloc_get_xlat_entry(op_array->literals)) {
+ zend_literal *p = op_array->literals;
+ zend_literal *end = p + op_array->last_literal;
+ ADD_DUP_SIZE(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
+ while (p < end) {
+ ADD_SIZE(zend_persist_zval_calc(&p->constant TSRMLS_CC));
+ p++;
+ }
+ }
+#endif
+
+ if (!zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
+#if ZEND_EXTENSION_API_NO <= PHP_5_3_X_API_NO
+ zend_op *opline = op_array->opcodes;
+ zend_op *end = op_array->opcodes + op_array->last;
+
+ ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last);
+ while (opline<end) {
+ if (opline->op1.op_type == IS_CONST) {
+ ADD_SIZE(zend_persist_zval_calc(&opline->op1.u.constant TSRMLS_CC));
+ }
+ if (opline->op2.op_type == IS_CONST) {
+ ADD_SIZE(zend_persist_zval_calc(&opline->op2.u.constant TSRMLS_CC));
+ }
+ opline++;
+ }
+#else
+ ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last);
+#endif
+ }
+
+ if (op_array->function_name) {
+ ADD_DUP_SIZE(op_array->function_name, strlen(op_array->function_name) + 1);
+ }
+
+ if (op_array->arg_info &&
+ !zend_shared_alloc_get_xlat_entry(op_array->arg_info)) {
+ zend_uint i;
+
+ ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
+ for (i = 0; i < op_array->num_args; i++) {
+ if (op_array->arg_info[i].name) {
+ ADD_INTERNED_STRING(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
+ }
+ if (op_array->arg_info[i].class_name) {
+ ADD_INTERNED_STRING(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
+ }
+
+ }
+ }
+
+ if (op_array->brk_cont_array) {
+ ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
+ }
+
+ if (op_array->static_variables) {
+ ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
+ ADD_SIZE(zend_hash_persist_calc(op_array->static_variables, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC));
+ }
+
+ if (ZCG(accel_directives).save_comments && op_array->doc_comment) {
+ ADD_DUP_SIZE(op_array->doc_comment, op_array->doc_comment_len + 1);
+ }
+
+ if (op_array->try_catch_array) {
+ ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
+ }
+
+ if (op_array->vars && !zend_shared_alloc_get_xlat_entry(op_array->vars)) {
+ int i;
+
+ ADD_DUP_SIZE(op_array->vars, sizeof(zend_compiled_variable) * op_array->last_var);
+ for (i = 0; i < op_array->last_var; i++) {
+ ADD_INTERNED_STRING(op_array->vars[i].name, op_array->vars[i].name_len + 1);
+ }
+ }
+
+ RETURN_SIZE();
+}
+
+static uint zend_persist_property_info_calc(zend_property_info *prop TSRMLS_DC)
+{
+ START_SIZE();
+ ADD_INTERNED_STRING(prop->name, prop->name_length + 1);
+ if (ZCG(accel_directives).save_comments && prop->doc_comment) {
+ ADD_DUP_SIZE(prop->doc_comment, prop->doc_comment_len + 1);
+ }
+ RETURN_SIZE();
+}
+
+static uint zend_persist_class_entry_calc(zend_class_entry **pce TSRMLS_DC)
+{
+ zend_class_entry *ce = *pce;
+ START_SIZE();
+
+ if (ce->type == ZEND_USER_CLASS) {
+ ADD_DUP_SIZE(ce, sizeof(zend_class_entry));
+ ADD_INTERNED_STRING(ce->name, ce->name_length + 1);
+ ADD_SIZE(zend_hash_persist_calc(&ce->function_table, (int (*)(void* TSRMLS_DC)) zend_persist_op_array_calc, sizeof(zend_op_array) TSRMLS_CC));
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ce->default_properties_table) {
+ int i;
+
+ ADD_SIZE(sizeof(zval*) * ce->default_properties_count);
+ for (i = 0; i < ce->default_properties_count; i++) {
+ if (ce->default_properties_table[i]) {
+ ADD_SIZE(zend_persist_zval_ptr_calc(&ce->default_properties_table[i] TSRMLS_CC));
+ }
+ }
+ }
+ if (ce->default_static_members_table) {
+ int i;
+
+ ADD_SIZE(sizeof(zval*) * ce->default_static_members_count);
+ for (i = 0; i < ce->default_static_members_count; i++) {
+ if (ce->default_static_members_table[i]) {
+ ADD_SIZE(zend_persist_zval_ptr_calc(&ce->default_static_members_table[i] TSRMLS_CC));
+ }
+ }
+ }
+#else
+ ADD_SIZE(zend_hash_persist_calc(&ce->default_properties, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC));
+ ADD_SIZE(zend_hash_persist_calc(&ce->default_static_members, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC));
+#endif
+ ADD_SIZE(zend_hash_persist_calc(&ce->constants_table, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC));
+
+ if (ZEND_CE_FILENAME(ce)) {
+ ADD_DUP_SIZE(ZEND_CE_FILENAME(ce), strlen(ZEND_CE_FILENAME(ce)) + 1);
+ }
+ if (ZCG(accel_directives).save_comments && ZEND_CE_DOC_COMMENT(ce)) {
+ ADD_DUP_SIZE(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce) + 1);
+ }
+
+ ADD_SIZE(zend_hash_persist_calc(&ce->properties_info, (int (*)(void* TSRMLS_DC)) zend_persist_property_info_calc, sizeof(zend_property_info) TSRMLS_CC));
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (ce->trait_aliases) {
+ int i = 0;
+ while (ce->trait_aliases[i]) {
+ if (ce->trait_aliases[i]->trait_method) {
+ if (ce->trait_aliases[i]->trait_method->method_name) {
+ ADD_SIZE(ce->trait_aliases[i]->trait_method->mname_len + 1);
+ }
+ if (ce->trait_aliases[i]->trait_method->class_name) {
+ ADD_SIZE(ce->trait_aliases[i]->trait_method->cname_len + 1);
+ }
+ ADD_SIZE(sizeof(zend_trait_method_reference));
+ }
+
+ if (ce->trait_aliases[i]->alias) {
+ ADD_SIZE(ce->trait_aliases[i]->alias_len + 1);
+ }
+ ADD_SIZE(sizeof(zend_trait_alias));
+ i++;
+ }
+ ADD_SIZE(sizeof(zend_trait_alias*) * (i + 1));
+ }
+
+ if (ce->trait_precedences) {
+ int i = 0;
+
+ while (ce->trait_precedences[i]) {
+ ADD_SIZE(ce->trait_precedences[i]->trait_method->mname_len + 1);
+ ADD_SIZE(ce->trait_precedences[i]->trait_method->cname_len + 1);
+ ADD_SIZE(sizeof(zend_trait_method_reference));
+
+ if (ce->trait_precedences[i]->exclude_from_classes) {
+ int j = 0;
+
+ while (ce->trait_precedences[i]->exclude_from_classes[j]) {
+ ADD_SIZE(strlen((char*)ce->trait_precedences[i]->exclude_from_classes[j]) + 1);
+ j++;
+ }
+ ADD_SIZE(sizeof(zend_class_entry*) * (j + 1));
+ }
+ ADD_SIZE(sizeof(zend_trait_precedence));
+ i++;
+ }
+ ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1));
+ }
+#endif
+ }
+ RETURN_SIZE();
+}
+
+static uint zend_accel_persist_class_table_calc(HashTable *class_table TSRMLS_DC)
+{
+ return zend_hash_persist_calc(class_table, (int (*)(void* TSRMLS_DC)) zend_persist_class_entry_calc, sizeof(zend_class_entry*) TSRMLS_CC);
+}
+
+uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length TSRMLS_DC)
+{
+ START_SIZE();
+
+ ADD_SIZE(zend_hash_persist_calc(&new_persistent_script->function_table, (int (*)(void* TSRMLS_DC)) zend_persist_op_array_calc, sizeof(zend_op_array) TSRMLS_CC));
+ ADD_SIZE(zend_accel_persist_class_table_calc(&new_persistent_script->class_table TSRMLS_CC));
+ ADD_SIZE(zend_persist_op_array_calc(&new_persistent_script->main_op_array TSRMLS_CC));
+ ADD_DUP_SIZE(key, key_length + 1);
+ ADD_DUP_SIZE(new_persistent_script->full_path, new_persistent_script->full_path_len + 1);
+ ADD_DUP_SIZE(new_persistent_script, sizeof(zend_persistent_script));
+
+ RETURN_SIZE();
+}
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
new file mode 100644
index 000000000..f4465ce78
--- /dev/null
+++ b/ext/opcache/zend_shared_alloc.c
@@ -0,0 +1,489 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <errno.h>
+#include "ZendAccelerator.h"
+#include "zend_shared_alloc.h"
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#ifndef ZEND_WIN32
+# include <sys/types.h>
+# include <dirent.h>
+# include <signal.h>
+# include <sys/stat.h>
+# include <stdio.h>
+#endif
+
+#ifdef HAVE_MPROTECT
+# include "sys/mman.h"
+#endif
+
+#define TMP_DIR "/tmp"
+#define SEM_FILENAME_PREFIX ".ZendSem."
+#define S_H(s) g_shared_alloc_handler->s
+
+/* True globals */
+/* old/new mapping. We can use true global even for ZTS because its usage
+ is wrapped with exclusive lock anyway */
+static HashTable xlat_table;
+static const zend_shared_memory_handlers *g_shared_alloc_handler = NULL;
+static const char *g_shared_model;
+/* pointer to globals allocated in SHM and shared across processes */
+zend_smm_shared_globals *smm_shared_globals;
+
+#ifndef ZEND_WIN32
+#ifdef ZTS
+static MUTEX_T zts_lock;
+#endif
+int lock_file;
+static char lockfile_name[sizeof(TMP_DIR) + sizeof(SEM_FILENAME_PREFIX) + 8];
+#endif
+
+static const zend_shared_memory_handler_entry handler_table[] = {
+#ifdef USE_MMAP
+ { "mmap", &zend_alloc_mmap_handlers },
+#endif
+#ifdef USE_SHM
+ { "shm", &zend_alloc_shm_handlers },
+#endif
+#ifdef USE_SHM_OPEN
+ { "posix", &zend_alloc_posix_handlers },
+#endif
+#ifdef ZEND_WIN32
+ { "win32", &zend_alloc_win32_handlers },
+#endif
+ { NULL, NULL}
+};
+
+#ifndef ZEND_WIN32
+void zend_shared_alloc_create_lock(void)
+{
+ int val;
+
+#ifdef ZTS
+ zts_lock = tsrm_mutex_alloc();
+#endif
+
+ sprintf(lockfile_name, "%s/%sXXXXXX", TMP_DIR, SEM_FILENAME_PREFIX);
+ lock_file = mkstemp(lockfile_name);
+ fchmod(lock_file, 0666);
+
+ if (lock_file == -1) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno);
+ }
+ val = fcntl(lock_file, F_GETFD, 0);
+ val |= FD_CLOEXEC;
+ fcntl(lock_file, F_SETFD, val);
+
+ unlink(lockfile_name);
+}
+#endif
+
+static void no_memory_bailout(int allocate_size, char *error)
+{
+ zend_accel_error(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %d bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno );
+}
+
+static void copy_shared_segments(void *to, void *from, int count, int size)
+{
+ zend_shared_segment **shared_segments_v = (zend_shared_segment **)to;
+ void *shared_segments_to_p = ((char *)to + count*(sizeof(void *)));
+ void *shared_segments_from_p = from;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ shared_segments_v[i] = shared_segments_to_p;
+ memcpy(shared_segments_to_p, shared_segments_from_p, size);
+ shared_segments_to_p = ((char *)shared_segments_to_p + size);
+ shared_segments_from_p = ((char *)shared_segments_from_p + size);
+ }
+}
+
+static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, int requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
+{
+ int res;
+ g_shared_alloc_handler = he->handler;
+ g_shared_model = he->name;
+ ZSMMG(shared_segments) = NULL;
+ ZSMMG(shared_segments_count) = 0;
+
+ res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
+
+ if (res) {
+ /* this model works! */
+ return res;
+ }
+ if (*shared_segments_p) {
+ int i;
+ /* cleanup */
+ for (i = 0; i < *shared_segments_count; i++) {
+ if ((*shared_segments_p)[i]->p && (int)(*shared_segments_p)[i]->p != -1) {
+ S_H(detach_segment)((*shared_segments_p)[i]);
+ }
+ }
+ free(*shared_segments_p);
+ *shared_segments_p = NULL;
+ }
+ g_shared_alloc_handler = NULL;
+ return ALLOC_FAILURE;
+}
+
+int zend_shared_alloc_startup(int requested_size)
+{
+ zend_shared_segment **tmp_shared_segments;
+ size_t shared_segments_array_size;
+ zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
+ char *error_in = NULL;
+ const zend_shared_memory_handler_entry *he;
+ int res = ALLOC_FAILURE;
+
+ TSRMLS_FETCH();
+
+ /* shared_free must be valid before we call zend_shared_alloc()
+ * - make it temporarily point to a local variable
+ */
+ smm_shared_globals = &tmp_shared_globals;
+ ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */
+
+ zend_shared_alloc_create_lock();
+
+ if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) {
+ char *model = ZCG(accel_directives).memory_model;
+ /* "cgi" is really "shm"... */
+ if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) {
+ model = "shm";
+ }
+
+ for (he = handler_table; he->name; he++) {
+ if (strcmp(model, he->name) == 0) {
+ res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
+ if (res) {
+ /* this model works! */
+ }
+ break;
+ }
+ }
+ }
+
+ if (res == FAILED_REATTACHED) {
+ smm_shared_globals = NULL;
+ return res;
+ }
+
+ if (!g_shared_alloc_handler) {
+ /* try memory handlers in order */
+ for (he = handler_table; he->name; he++) {
+ res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
+ if (res) {
+ /* this model works! */
+ break;
+ }
+ }
+ }
+
+ if (!g_shared_alloc_handler) {
+ no_memory_bailout(requested_size, error_in);
+ return ALLOC_FAILURE;
+ }
+
+ if (res == SUCCESSFULLY_REATTACHED) {
+ return res;
+ }
+
+ shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
+
+ /* move shared_segments and shared_free to shared memory */
+ ZCG(locked) = 1; /* no need to perform a real lock at this point */
+ p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
+
+ tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
+ copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
+
+ *p_tmp_shared_globals = tmp_shared_globals;
+ smm_shared_globals = p_tmp_shared_globals;
+
+ free(ZSMMG(shared_segments));
+ ZSMMG(shared_segments) = tmp_shared_segments;
+
+ ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count));
+ ZCG(locked) = 0;
+
+ return res;
+}
+
+void zend_shared_alloc_shutdown(void)
+{
+ zend_shared_segment **tmp_shared_segments;
+ size_t shared_segments_array_size;
+ zend_smm_shared_globals tmp_shared_globals;
+ int i;
+
+ tmp_shared_globals = *smm_shared_globals;
+ smm_shared_globals = &tmp_shared_globals;
+ shared_segments_array_size = ZSMMG(shared_segments_count) * (S_H(segment_type_size)() + sizeof(void *));
+ tmp_shared_segments = emalloc(shared_segments_array_size);
+ copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
+ ZSMMG(shared_segments) = tmp_shared_segments;
+
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ S_H(detach_segment)(ZSMMG(shared_segments)[i]);
+ }
+ efree(ZSMMG(shared_segments));
+ ZSMMG(shared_segments) = NULL;
+ g_shared_alloc_handler = NULL;
+#ifndef ZEND_WIN32
+ close(lock_file);
+#endif
+}
+
+static size_t zend_shared_alloc_get_largest_free_block(void)
+{
+ int i;
+ size_t largest_block_size = 0;
+
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ size_t block_size = ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos;
+
+ if (block_size>largest_block_size) {
+ largest_block_size = block_size;
+ }
+ }
+ return largest_block_size;
+}
+
+#define MIN_FREE_MEMORY 64*1024
+
+#define SHARED_ALLOC_FAILED() do { \
+ zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %ld bytes (%ld bytes free)", (long)size, (long)ZSMMG(shared_free)); \
+ if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \
+ ZSMMG(memory_exhausted) = 1; \
+ zend_accel_schedule_restart(ACCEL_RESTART_OOM TSRMLS_CC); \
+ } \
+ } while (0)
+
+void *zend_shared_alloc(size_t size)
+{
+ int i;
+ unsigned int block_size = size + sizeof(zend_shared_memory_block_header);
+ TSRMLS_FETCH();
+
+#if 1
+ if (!ZCG(locked)) {
+ zend_accel_error(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
+ }
+#endif
+ if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */
+ SHARED_ALLOC_FAILED();
+ return NULL;
+ }
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
+ zend_shared_memory_block_header *p = (zend_shared_memory_block_header *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
+ int remainder = block_size % PLATFORM_ALIGNMENT;
+ void *retval;
+
+ if (remainder != 0) {
+ size += PLATFORM_ALIGNMENT - remainder;
+ block_size += PLATFORM_ALIGNMENT - remainder;
+ }
+ ZSMMG(shared_segments)[i]->pos += block_size;
+ ZSMMG(shared_free) -= block_size;
+ p->size = size;
+ retval = ((char *) p) + sizeof(zend_shared_memory_block_header);
+ memset(retval, 0, size);
+ return retval;
+ }
+ }
+ SHARED_ALLOC_FAILED();
+ return NULL;
+}
+
+int zend_shared_memdup_size(void *source, size_t size)
+{
+ void **old_p;
+
+ if (zend_hash_index_find(&xlat_table, (ulong)source, (void **)&old_p) == SUCCESS) {
+ /* we already duplicated this pointer */
+ return 0;
+ }
+ zend_shared_alloc_register_xlat_entry(source, source);
+ return ZEND_ALIGNED_SIZE(size);
+}
+
+void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source TSRMLS_DC)
+{
+ void **old_p, *retval;
+
+ if (zend_hash_index_find(&xlat_table, (ulong)source, (void **)&old_p) == SUCCESS) {
+ /* we already duplicated this pointer */
+ return *old_p;
+ }
+ retval = ZCG(mem);;
+ ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
+ memcpy(retval, source, size);
+ if (free_source) {
+ interned_efree((char*)source);
+ }
+ zend_shared_alloc_register_xlat_entry(source, retval);
+ return retval;
+}
+
+void zend_shared_alloc_safe_unlock(TSRMLS_D)
+{
+ if (ZCG(locked)) {
+ zend_shared_alloc_unlock(TSRMLS_C);
+ }
+}
+
+#ifndef ZEND_WIN32
+/* name l_type l_whence l_start l_len */
+static FLOCK_STRUCTURE(mem_write_lock, F_WRLCK, SEEK_SET, 0, 1);
+static FLOCK_STRUCTURE(mem_write_unlock, F_UNLCK, SEEK_SET, 0, 1);
+#endif
+
+void zend_shared_alloc_lock(TSRMLS_D)
+{
+#ifndef ZEND_WIN32
+
+#ifdef ZTS
+ tsrm_mutex_lock(zts_lock);
+#endif
+
+#if 0
+ /* this will happen once per process, and will un-globalize mem_write_lock */
+ if (mem_write_lock.l_pid == -1) {
+ mem_write_lock.l_pid = getpid();
+ }
+#endif
+
+ while (1) {
+ if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ zend_accel_error(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno);
+ }
+ break;
+ }
+#else
+ zend_shared_alloc_lock_win32();
+#endif
+
+ ZCG(locked) = 1;
+
+ /* Prepare translation table
+ *
+ * Make it persistent so that it uses malloc() and allocated blocks
+ * won't be taken from space which is freed by efree in memdup.
+ * Otherwise it leads to false matches in memdup check.
+ */
+ zend_hash_init(&xlat_table, 100, NULL, NULL, 1);
+}
+
+void zend_shared_alloc_unlock(TSRMLS_D)
+{
+ /* Destroy translation table */
+ zend_hash_destroy(&xlat_table);
+
+ ZCG(locked) = 0;
+
+#ifndef ZEND_WIN32
+ if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) {
+ zend_accel_error(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno);
+ }
+#ifdef ZTS
+ tsrm_mutex_unlock(zts_lock);
+#endif
+#else
+ zend_shared_alloc_unlock_win32();
+#endif
+}
+
+void zend_shared_alloc_clear_xlat_table(void)
+{
+ zend_hash_clean(&xlat_table);
+}
+
+void zend_shared_alloc_register_xlat_entry(const void *old, const void *new)
+{
+ zend_hash_index_update(&xlat_table, (ulong)old, (void*)&new, sizeof(void *), NULL);
+}
+
+void *zend_shared_alloc_get_xlat_entry(const void *old)
+{
+ void **retval;
+
+ if (zend_hash_index_find(&xlat_table, (ulong)old, (void **)&retval) == FAILURE) {
+ return NULL;
+ }
+ return *retval;
+}
+
+size_t zend_shared_alloc_get_free_memory(void)
+{
+ return ZSMMG(shared_free);
+}
+
+void zend_shared_alloc_save_state(void)
+{
+ int i;
+
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos;
+ }
+ ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free);
+}
+
+void zend_shared_alloc_restore_state(void)
+{
+ int i;
+
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ ZSMMG(shared_segments)[i]->pos = ZSMMG(shared_memory_state).positions[i];
+ }
+ ZSMMG(shared_free) = ZSMMG(shared_memory_state).shared_free;
+ ZSMMG(memory_exhausted) = 0;
+ ZSMMG(wasted_shared_memory) = 0;
+}
+
+const char *zend_accel_get_shared_model(void)
+{
+ return g_shared_model;
+}
+
+void zend_accel_shared_protect(int mode TSRMLS_DC)
+{
+#ifdef HAVE_MPROTECT
+ int i;
+
+ if (mode) {
+ mode = PROT_READ;
+ } else {
+ mode = PROT_READ|PROT_WRITE;
+ }
+
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->size, mode);
+ }
+#endif
+}
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
new file mode 100644
index 000000000..23af630f8
--- /dev/null
+++ b/ext/opcache/zend_shared_alloc.h
@@ -0,0 +1,186 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2013 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: |
+ | http://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@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Stanislav Malyshev <stas@zend.com> |
+ | Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_SHARED_ALLOC_H
+#define ZEND_SHARED_ALLOC_H
+
+#include "zend.h"
+#include "ZendAccelerator.h"
+
+#if defined(__APPLE__) && defined(__MACH__) /* darwin */
+# ifdef HAVE_SHM_MMAP_POSIX
+# define USE_SHM_OPEN 1
+# endif
+# ifdef HAVE_SHM_MMAP_ANON
+# define USE_MMAP 1
+# endif
+#elif defined(__linux__) || defined(_AIX)
+# ifdef HAVE_SHM_IPC
+# define USE_SHM 1
+# endif
+# ifdef HAVE_SHM_MMAP_ANON
+# define USE_MMAP 1
+# endif
+#elif defined(__sparc) || defined(__sun)
+# ifdef HAVE_SHM_MMAP_POSIX
+# define USE_SHM_OPEN 1
+# endif
+# ifdef HAVE_SHM_IPC
+# define USE_SHM 1
+# endif
+# if defined(__i386)
+# ifdef HAVE_SHM_MMAP_ANON
+# define USE_MMAP 1
+# endif
+# endif
+#else
+# ifdef HAVE_SHM_MMAP_POSIX
+# define USE_SHM_OPEN 1
+# endif
+# ifdef HAVE_SHM_MMAP_ANON
+# define USE_MMAP 1
+# endif
+# ifdef HAVE_SHM_IPC
+# define USE_SHM 1
+# endif
+#endif
+
+#define ALLOC_FAILURE 0
+#define ALLOC_SUCCESS 1
+#define FAILED_REATTACHED 2
+#define SUCCESSFULLY_REATTACHED 4
+#define ALLOC_FAIL_MAPPING 8
+
+typedef struct _zend_shared_segment {
+ size_t size;
+ size_t pos; /* position for simple stack allocator */
+ void *p;
+} zend_shared_segment;
+
+typedef int (*create_segments_t)(size_t requested_size, zend_shared_segment ***shared_segments, int *shared_segment_count, char **error_in);
+typedef int (*detach_segment_t)(zend_shared_segment *shared_segment);
+
+typedef struct {
+ create_segments_t create_segments;
+ detach_segment_t detach_segment;
+ size_t (*segment_type_size)(void);
+} zend_shared_memory_handlers;
+
+typedef struct _handler_entry {
+ const char *name;
+ zend_shared_memory_handlers *handler;
+} zend_shared_memory_handler_entry;
+
+typedef struct _zend_shared_memory_block_header {
+ int size;
+} zend_shared_memory_block_header;
+
+typedef struct _zend_shared_memory_state {
+ int *positions; /* current positions for each segment */
+ int shared_free; /* amount of free shared memory */
+} zend_shared_memory_state;
+
+typedef struct _zend_smm_shared_globals {
+ /* Shared Memory Manager */
+ zend_shared_segment **shared_segments;
+ /* Number of allocated shared segments */
+ int shared_segments_count;
+ /* Amount of free shared memory */
+ size_t shared_free;
+ /* Amount of shared memory allocated by garbage */
+ int wasted_shared_memory;
+ /* No more shared memory flag */
+ zend_bool memory_exhausted;
+ /* Saved Shared Allocator State */
+ zend_shared_memory_state shared_memory_state;
+ /* Pointer to the application's shared data structures */
+ void *app_shared_globals;
+} zend_smm_shared_globals;
+
+extern zend_smm_shared_globals *smm_shared_globals;
+
+#define ZSMMG(element) (smm_shared_globals->element)
+
+#define SHARED_ALLOC_REATTACHED (SUCCESS+1)
+
+int zend_shared_alloc_startup(int requested_size);
+void zend_shared_alloc_shutdown(void);
+
+/* allocate shared memory block */
+void *zend_shared_alloc(size_t size);
+
+/* copy into shared memory */
+void *_zend_shared_memdup(void *p, size_t size, zend_bool free_source TSRMLS_DC);
+int zend_shared_memdup_size(void *p, size_t size);
+
+typedef union _align_test {
+ void *ptr;
+ double dbl;
+ long lng;
+} align_test;
+
+#if ZEND_GCC_VERSION >= 2000
+# define PLATFORM_ALIGNMENT (__alignof__ (align_test))
+#else
+# define PLATFORM_ALIGNMENT (sizeof(align_test))
+#endif
+
+#define ZEND_ALIGNED_SIZE(size) \
+ ((size + PLATFORM_ALIGNMENT - 1) & ~(PLATFORM_ALIGNMENT - 1))
+
+/* exclusive locking */
+void zend_shared_alloc_lock(TSRMLS_D);
+void zend_shared_alloc_unlock(TSRMLS_D); /* returns the allocated size during lock..unlock */
+void zend_shared_alloc_safe_unlock(TSRMLS_D);
+
+/* old/new mapping functions */
+void zend_shared_alloc_clear_xlat_table(void);
+void zend_shared_alloc_register_xlat_entry(const void *old, const void *new);
+void *zend_shared_alloc_get_xlat_entry(const void *old);
+
+size_t zend_shared_alloc_get_free_memory(void);
+void zend_shared_alloc_save_state(void);
+void zend_shared_alloc_restore_state(void);
+const char *zend_accel_get_shared_model(void);
+
+/* memory write protection */
+void zend_accel_shared_protect(int mode TSRMLS_DC);
+
+#ifdef USE_MMAP
+extern zend_shared_memory_handlers zend_alloc_mmap_handlers;
+#endif
+
+#ifdef USE_SHM
+extern zend_shared_memory_handlers zend_alloc_shm_handlers;
+#endif
+
+#ifdef USE_SHM_OPEN
+extern zend_shared_memory_handlers zend_alloc_posix_handlers;
+#endif
+
+#ifdef ZEND_WIN32
+extern zend_shared_memory_handlers zend_alloc_win32_handlers;
+void zend_shared_alloc_create_lock(void);
+void zend_shared_alloc_lock_win32(void);
+void zend_shared_alloc_unlock_win32(void);
+#endif
+
+#endif /* ZEND_SHARED_ALLOC_H */
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index b1ee89a8a..7d34d9feb 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -251,7 +251,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
char *tmp = NULL;
#if HAVE_SETLOCALE
-# ifdef PHP_WIN32 && ZTS
+# if defined(PHP_WIN32) && defined(ZTS)
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
# endif
locale = setlocale(LC_CTYPE, NULL);
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 5dc445ff8..1b0db91c3 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -2499,16 +2499,15 @@ static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRM
*data = &I->fetch_ahead;
}
-static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
- ulong *int_key TSRMLS_DC)
+static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
if (I->key == (ulong)-1) {
- return HASH_KEY_NON_EXISTANT;
+ ZVAL_NULL(key);
+ } else {
+ ZVAL_LONG(key, I->key);
}
- *int_key = I->key;
- return HASH_KEY_IS_LONG;
}
static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c
index f2e36c171..2ae559571 100644
--- a/ext/pdo_mysql/mysql_statement.c
+++ b/ext/pdo_mysql/mysql_statement.c
@@ -343,7 +343,6 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
pdo_mysql_db_handle *H = S->H;
long row_count;
- int ret;
PDO_DBG_ENTER("pdo_mysql_stmt_next_rowset");
PDO_DBG_INF_FMT("stmt=%p", S->stmt);
@@ -412,26 +411,21 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
S->result = NULL;
}
- ret = mysql_next_result(H->server);
+ if (!mysql_more_results(H->server)) {
+ /* No more results */
+ PDO_DBG_RETURN(0);
+ }
#if PDO_USE_MYSQLND
- /* for whatever reason mysqlnd breaks with libmysql compatibility at the C level, no -1 */
- if (PASS != ret) {
+ if (mysql_next_result(H->server) == FAIL) {
pdo_mysql_error_stmt(stmt);
PDO_DBG_RETURN(0);
- }
- if (mysql_more_results(H->server)) {
- PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
} else {
- /* No more results */
- PDO_DBG_RETURN(0);
+ PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
}
#else
- if (ret > 0) {
+ if (mysql_next_result(H->server) > 0) {
pdo_mysql_error_stmt(stmt);
PDO_DBG_RETURN(0);
- } else if (ret < 0) {
- /* No more results */
- PDO_DBG_RETURN(0);
} else {
PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
}
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
index a6dd2c814..94ffd3744 100644
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -1434,16 +1434,13 @@ struct _phar_t {
static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
{
zval **value;
- zend_uchar key_type;
zend_bool close_fp = 1;
- ulong int_key;
struct _phar_t *p_obj = (struct _phar_t*) puser;
uint str_key_len, base_len = p_obj->l, fname_len;
phar_entry_data *data;
php_stream *fp;
size_t contents_len;
char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
- phar_zstr key;
char *str_key;
zend_class_entry *ce = p_obj->c;
phar_archive_object *phar_obj = p_obj->p;
@@ -1478,35 +1475,24 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{
}
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
+ zval key;
+ iter->funcs->get_current_key(iter, &key TSRMLS_CC);
if (EG(exception)) {
return ZEND_HASH_APPLY_STOP;
}
- if (key_type == HASH_KEY_IS_LONG) {
+ if (Z_TYPE(key) != IS_STRING) {
+ zval_dtor(&key);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
- if (key_type > 9) { /* IS_UNICODE == 10 */
-#if PHP_VERSION_ID < 60000
-/* this can never happen, but fixes a compile warning */
- spprintf(&str_key, 0, "%s", key);
-#else
- spprintf(&str_key, 0, "%v", key);
- ezfree(key);
-#endif
- } else {
- PHAR_STR(key, str_key);
- }
+ str_key_len = Z_STRLEN(key);
+ str_key = estrndup(Z_STRVAL(key), str_key_len);
save = str_key;
-
- if (str_key[str_key_len - 1] == '\0') {
- str_key_len--;
- }
-
+ zval_dtor(&key);
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
@@ -1641,32 +1627,24 @@ phar_spl_fileinfo:
}
} else {
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
+ zval key;
+ iter->funcs->get_current_key(iter, &key TSRMLS_CC);
if (EG(exception)) {
return ZEND_HASH_APPLY_STOP;
}
- if (key_type == HASH_KEY_IS_LONG) {
+ if (Z_TYPE(key) != IS_STRING) {
+ zval_dtor(&key);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
}
- if (key_type > 9) { /* IS_UNICODE == 10 */
-#if PHP_VERSION_ID < 60000
-/* this can never happen, but fixes a compile warning */
- spprintf(&str_key, 0, "%s", key);
-#else
- spprintf(&str_key, 0, "%v", key);
- ezfree(key);
-#endif
- } else {
- PHAR_STR(key, str_key);
- }
+ str_key_len = Z_STRLEN(key);
+ str_key = estrndup(Z_STRVAL(key), str_key_len);
save = str_key;
-
- if (str_key[str_key_len - 1] == '\0') str_key_len--;
+ zval_dtor(&key);
} else {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
return ZEND_HASH_APPLY_STOP;
diff --git a/ext/phar/tests/create_new_and_modify.phpt b/ext/phar/tests/create_new_and_modify.phpt
index d6c469d9c..c03576cb2 100644
--- a/ext/phar/tests/create_new_and_modify.phpt
+++ b/ext/phar/tests/create_new_and_modify.phpt
@@ -21,6 +21,14 @@ $sig1 = $phar->getSignature();
include $pname . '/a.php';
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
file_put_contents($pname .'/a.php', "modified!\n");
file_put_contents($pname .'/b.php', "another!\n");
diff --git a/ext/phar/tests/delete_in_phar.phpt b/ext/phar/tests/delete_in_phar.phpt
index 4842d2791..d28f136f7 100644
--- a/ext/phar/tests/delete_in_phar.phpt
+++ b/ext/phar/tests/delete_in_phar.phpt
@@ -15,6 +15,15 @@ $files = array();
$files['a.php'] = '<?php echo "This is a\n"; ?>';
$files['b.php'] = '<?php echo "This is b\n"; ?>';
$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include 'files/phar_test.inc';
include $pname . '/a.php';
diff --git a/ext/phar/tests/delete_in_phar_confirm.phpt b/ext/phar/tests/delete_in_phar_confirm.phpt
index 13a8d0db2..0d4eb1e2a 100644
--- a/ext/phar/tests/delete_in_phar_confirm.phpt
+++ b/ext/phar/tests/delete_in_phar_confirm.phpt
@@ -15,6 +15,15 @@ $files = array();
$files['a.php'] = '<?php echo "This is a\n"; ?>';
$files['b.php'] = '<?php echo "This is b\n"; ?>';
$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include 'files/phar_test.inc';
include $pname . '/a.php';
diff --git a/ext/phar/tests/tar/create_new_and_modify.phpt b/ext/phar/tests/tar/create_new_and_modify.phpt
index 8062fda76..905bfabc8 100644
--- a/ext/phar/tests/tar/create_new_and_modify.phpt
+++ b/ext/phar/tests/tar/create_new_and_modify.phpt
@@ -15,6 +15,14 @@ $pname = 'phar://' . $fname;
file_put_contents($pname . '/a.php', "brand new!\n");
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
$phar = new Phar($fname);
var_dump($phar->isFileFormat(Phar::TAR));
$sig1 = md5_file($fname);
diff --git a/ext/phar/tests/tar/delete_in_phar.phpt b/ext/phar/tests/tar/delete_in_phar.phpt
index 91ef4a204..1982b6bda 100644
--- a/ext/phar/tests/tar/delete_in_phar.phpt
+++ b/ext/phar/tests/tar/delete_in_phar.phpt
@@ -18,6 +18,14 @@ $phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include $alias . '/a.php';
include $alias . '/b.php';
include $alias . '/b/c.php';
diff --git a/ext/phar/tests/tar/delete_in_phar_confirm.phpt b/ext/phar/tests/tar/delete_in_phar_confirm.phpt
index 707bcbd0e..7593ebc1f 100644
--- a/ext/phar/tests/tar/delete_in_phar_confirm.phpt
+++ b/ext/phar/tests/tar/delete_in_phar_confirm.phpt
@@ -18,6 +18,14 @@ $phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include $alias . '/a.php';
include $alias . '/b.php';
include $alias . '/b/c.php';
diff --git a/ext/phar/tests/zip/create_new_and_modify.phpt b/ext/phar/tests/zip/create_new_and_modify.phpt
index 5a3ec3317..55d69cca0 100644
--- a/ext/phar/tests/zip/create_new_and_modify.phpt
+++ b/ext/phar/tests/zip/create_new_and_modify.phpt
@@ -15,6 +15,14 @@ $pname = 'phar://' . $fname;
file_put_contents($pname . '/a.php', "brand new!\n");
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
$phar = new Phar($fname);
var_dump($phar->isFileFormat(Phar::ZIP));
$sig1 = md5_file($fname);
diff --git a/ext/phar/tests/zip/delete_in_phar.phpt b/ext/phar/tests/zip/delete_in_phar.phpt
index b7bda7ca4..f01280013 100644
--- a/ext/phar/tests/zip/delete_in_phar.phpt
+++ b/ext/phar/tests/zip/delete_in_phar.phpt
@@ -18,6 +18,14 @@ $phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include $alias . '/a.php';
include $alias . '/b.php';
include $alias . '/b/c.php';
diff --git a/ext/phar/tests/zip/delete_in_phar_confirm.phpt b/ext/phar/tests/zip/delete_in_phar_confirm.phpt
index fdd0b42b5..008049917 100644
--- a/ext/phar/tests/zip/delete_in_phar_confirm.phpt
+++ b/ext/phar/tests/zip/delete_in_phar_confirm.phpt
@@ -18,6 +18,14 @@ $phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
+if (function_exists("opcache_get_status")) {
+ $status = opcache_get_status();
+ if ($status["opcache_enabled"]) {
+ ini_set("opcache.revalidate_freq", "0");
+ sleep(2);
+ }
+}
+
include $alias . '/a.php';
include $alias . '/b.php';
include $alias . '/b/c.php';
diff --git a/ext/reflection/tests/005.phpt b/ext/reflection/tests/005.phpt
index f337e44ae..e257699b6 100644
--- a/ext/reflection/tests/005.phpt
+++ b/ext/reflection/tests/005.phpt
@@ -1,5 +1,8 @@
--TEST--
ReflectionMethod::getDocComment() uses wrong comment block
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/009.phpt b/ext/reflection/tests/009.phpt
index e96b21eba..b54e89e5b 100644
--- a/ext/reflection/tests/009.phpt
+++ b/ext/reflection/tests/009.phpt
@@ -1,5 +1,8 @@
--TEST--
ReflectionFunction basic tests
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/025.phpt b/ext/reflection/tests/025.phpt
index a5f604f56..92002007b 100644
--- a/ext/reflection/tests/025.phpt
+++ b/ext/reflection/tests/025.phpt
@@ -2,6 +2,9 @@
ReflectionFunction basic tests
--SKIPIF--
<?php extension_loaded('reflection') or die('skip'); ?>
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/ReflectionClass_getDocComment_001.phpt b/ext/reflection/tests/ReflectionClass_getDocComment_001.phpt
index 5feb560ae..efa7e9a10 100644
--- a/ext/reflection/tests/ReflectionClass_getDocComment_001.phpt
+++ b/ext/reflection/tests/ReflectionClass_getDocComment_001.phpt
@@ -3,6 +3,9 @@ ReflectionClass::getDocComment()
--CREDITS--
Robin Fernandes <robinf@php.net>
Steve Seear <stevseea@php.net>
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
/**
diff --git a/ext/reflection/tests/ReflectionFunction_getDocComment.001.phpt b/ext/reflection/tests/ReflectionFunction_getDocComment.001.phpt
index 38c278d8a..68d1d9d3a 100644
--- a/ext/reflection/tests/ReflectionFunction_getDocComment.001.phpt
+++ b/ext/reflection/tests/ReflectionFunction_getDocComment.001.phpt
@@ -3,6 +3,9 @@ ReflectionFunction::getDocComment()
--CREDITS--
Robin Fernandes <robinf@php.net>
Steve Seear <stevseea@php.net>
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/ReflectionMethod_getDocComment_basic.phpt b/ext/reflection/tests/ReflectionMethod_getDocComment_basic.phpt
index c01f689cf..b04fb6c9f 100644
--- a/ext/reflection/tests/ReflectionMethod_getDocComment_basic.phpt
+++ b/ext/reflection/tests/ReflectionMethod_getDocComment_basic.phpt
@@ -1,5 +1,8 @@
--TEST--
ReflectionMethod::getDocComment()
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
/**
diff --git a/ext/reflection/tests/ReflectionProperty_basic2.phpt b/ext/reflection/tests/ReflectionProperty_basic2.phpt
index b7b21333d..bc42d3f82 100644
--- a/ext/reflection/tests/ReflectionProperty_basic2.phpt
+++ b/ext/reflection/tests/ReflectionProperty_basic2.phpt
@@ -1,5 +1,8 @@
--TEST--
Test usage of ReflectionProperty methods isDefault(), getModifiers(), getDeclaringClass() and getDocComment().
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/ReflectionProperty_getDocComment_basic.phpt b/ext/reflection/tests/ReflectionProperty_getDocComment_basic.phpt
index 2c4815a35..f94ee8ca4 100644
--- a/ext/reflection/tests/ReflectionProperty_getDocComment_basic.phpt
+++ b/ext/reflection/tests/ReflectionProperty_getDocComment_basic.phpt
@@ -1,5 +1,8 @@
--TEST--
Test ReflectionProperty::getDocComment() usage.
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
diff --git a/ext/reflection/tests/bug36308.phpt b/ext/reflection/tests/bug36308.phpt
index 79aa5f8fa..f923ee31a 100644
--- a/ext/reflection/tests/bug36308.phpt
+++ b/ext/reflection/tests/bug36308.phpt
@@ -1,5 +1,8 @@
--TEST--
Reflection Bug #36308 (ReflectionProperty::getDocComment() does not reflect extended class commentary)
+--INI--
+opcache.save_comments=1
+opcache.load_comments=1
--FILE--
<?php
class Base {
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 692516840..e7c2f2984 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -59,7 +59,7 @@ static zval *sxe_get_value(zval *z TSRMLS_DC);
static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC);
static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC);
static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
-static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC);
static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC);
static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC);
@@ -694,7 +694,7 @@ static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_D
}
/* }}} */
-static zval** sxe_property_get_adr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
+static zval** sxe_property_get_adr(zval *object, zval *member, int fetch_type, const zend_literal *key TSRMLS_DC) /* {{{ */
{
php_sxe_object *sxe;
xmlNodePtr node;
@@ -2376,29 +2376,22 @@ static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***da
}
/* }}} */
-static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
- zval *curobj;
- xmlNodePtr curnode = NULL;
- php_sxe_object *intern;
- int namelen;
-
php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
- curobj = iterator->sxe->iter.data;
+ zval *curobj = iterator->sxe->iter.data;
+ php_sxe_object *intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
- intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
+ xmlNodePtr curnode = NULL;
if (intern != NULL && intern->node != NULL) {
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
}
- if (!curnode) {
- return HASH_KEY_NON_EXISTANT;
- }
-
- namelen = xmlStrlen(curnode->name);
- *str_key = estrndup((char *)curnode->name, namelen);
- *str_key_len = namelen + 1;
- return HASH_KEY_IS_STRING;
+ if (curnode) {
+ ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1);
+ } else {
+ ZVAL_NULL(key);
+ }
}
/* }}} */
diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c
index 6f2f070f2..9789638c6 100644
--- a/ext/snmp/snmp.c
+++ b/ext/snmp/snmp.c
@@ -847,9 +847,9 @@ retry:
}
} else if (st & SNMP_USE_SUFFIX_AS_KEYS && st & SNMP_CMD_WALK) {
snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
- if (objid_query->vars[0].name_length <= vars->name_length && snmp_oid_compare(objid_query->vars[0].name, objid_query->vars[0].name_length, vars->name, objid_query->vars[0].name_length) == 0) {
+ if (rootlen <= vars->name_length && snmp_oid_compare(root, rootlen, vars->name, rootlen) == 0) {
buf2[0] = '\0';
- count = objid_query->vars[0].name_length;
+ count = rootlen;
while(count < vars->name_length){
sprintf(buf, "%lu.", vars->name[count]);
strcat(buf2, buf);
diff --git a/ext/snmp/tests/ipv6.phpt b/ext/snmp/tests/ipv6.phpt
index 12879416c..f5239e117 100644
--- a/ext/snmp/tests/ipv6.phpt
+++ b/ext/snmp/tests/ipv6.phpt
@@ -20,6 +20,10 @@ snmp_set_quick_print(false);
snmp_set_valueretrieval(SNMP_VALUE_PLAIN);
var_dump(snmpget($hostname6_port, $community, '.1.3.6.1.2.1.1.1.0'));
+var_dump(snmpget('[dead:beef::', $community, '.1.3.6.1.2.1.1.1.0'));
?>
--EXPECTF--
%unicode|string%(%d) "%s"
+
+Warning: snmpget(): malformed IPv6 address, closing square bracket missing in %s on line %d
+bool(false) \ No newline at end of file
diff --git a/ext/snmp/tests/snmp-object.phpt b/ext/snmp/tests/snmp-object.phpt
index 06b6492bd..522d417af 100644
--- a/ext/snmp/tests/snmp-object.phpt
+++ b/ext/snmp/tests/snmp-object.phpt
@@ -83,6 +83,19 @@ var_dump(gettype($z));
var_dump(count($z));
var_dump(key($z));
var_dump(array_shift($z));
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
+array_shift($z);
+var_dump(key($z));
var_dump($session->close());
echo "SNMPv3 (default security settings)\n";
@@ -194,6 +207,13 @@ string(5) "array"
int(%d)
string(3) "1.0"
string(%d) "%s"
+string(3) "2.0"
+string(3) "3.0"
+string(3) "4.0"
+string(3) "5.0"
+string(3) "6.0"
+string(3) "7.0"
+string(3) "8.0"
bool(true)
SNMPv3 (default security settings)
string(%d) "%S"
diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index 897956d91..5cec3e558 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -2313,10 +2313,6 @@ static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNod
zend_object_iterator *iter;
zend_class_entry *ce = Z_OBJCE_P(data);
zval **val;
- char *str_key;
- uint str_key_len;
- ulong int_key;
- int key_type;
ALLOC_ZVAL(array_copy);
INIT_PZVAL(array_copy);
@@ -2345,19 +2341,14 @@ static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNod
goto iterator_done;
}
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ zval key;
+ iter->funcs->get_current_key(iter, &key TSRMLS_CC);
if (EG(exception)) {
goto iterator_done;
}
- switch(key_type) {
- case HASH_KEY_IS_STRING:
- add_assoc_zval_ex(array_copy, str_key, str_key_len, *val);
- efree(str_key);
- break;
- case HASH_KEY_IS_LONG:
- add_index_zval(array_copy, int_key, *val);
- break;
- }
+ array_set_zval_key(Z_ARRVAL_P(array_copy), &key, *val);
+ zval_ptr_dtor(val);
+ zval_dtor(&key);
} else {
add_next_index_zval(array_copy, *val);
}
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index e56a8f09e..edeade375 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -1018,20 +1018,20 @@ static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***da
}
/* }}} */
-static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
spl_array_it *iterator = (spl_array_it *)iter;
spl_array_object *object = iterator->object;
HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
- return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
+ zend_user_it_get_current_key(iter, key TSRMLS_CC);
} else {
if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) {
- return HASH_KEY_NON_EXISTANT;
+ ZVAL_NULL(key);
+ } else {
+ zend_hash_get_current_key_zval_ex(aht, key, &object->pos);
}
-
- return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
}
}
/* }}} */
@@ -1547,25 +1547,13 @@ SPL_METHOD(Array, key)
void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
{
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
- char *string_key;
- uint string_length;
- ulong num_key;
HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
return;
}
- switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
- case HASH_KEY_IS_STRING:
- RETVAL_STRINGL(string_key, string_length - 1, 0);
- break;
- case HASH_KEY_IS_LONG:
- RETVAL_LONG(num_key);
- break;
- case HASH_KEY_NON_EXISTANT:
- return;
- }
+ zend_hash_get_current_key_zval_ex(aht, return_value, &intern->pos);
}
/* }}} */
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index f43a3709e..cf653f689 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -1621,7 +1621,7 @@ SPL_METHOD(GlobIterator, count)
static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC);
static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC);
static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
-static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC);
static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC);
@@ -1698,12 +1698,11 @@ static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval
/* }}} */
/* {{{ spl_filesystem_dir_it_current_key */
-static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
-
- *int_key = object->u.dir.index;
- return HASH_KEY_IS_LONG;
+
+ ZVAL_LONG(key, object->u.dir.index);
}
/* }}} */
@@ -1777,19 +1776,16 @@ static void spl_filesystem_tree_it_current_data(zend_object_iterator *iter, zval
/* }}} */
/* {{{ spl_filesystem_tree_it_current_key */
-static int spl_filesystem_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+static void spl_filesystem_tree_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
-
+
if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
- *str_key_len = strlen(object->u.dir.entry.d_name) + 1;
- *str_key = estrndup(object->u.dir.entry.d_name, *str_key_len - 1);
+ ZVAL_STRING(key, object->u.dir.entry.d_name, 1);
} else {
spl_filesystem_object_get_file_name(object TSRMLS_CC);
- *str_key_len = object->file_name_len + 1;
- *str_key = estrndup(object->file_name, object->file_name_len);
+ ZVAL_STRINGL(key, object->file_name, object->file_name_len, 1);
}
- return HASH_KEY_IS_STRING;
}
/* }}} */
diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c
index a8417fead..83610863e 100644
--- a/ext/spl/spl_dllist.c
+++ b/ext/spl/spl_dllist.c
@@ -794,7 +794,7 @@ SPL_METHOD(SplDoublyLinkedList, offsetGet)
intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
index = spl_offset_convert_to_long(zindex TSRMLS_CC);
- if (index < 0 || index >= intern->llist->count) {
+ if (index < 0 || index >= intern->llist->count) {
zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
return;
}
@@ -880,10 +880,10 @@ SPL_METHOD(SplDoublyLinkedList, offsetUnset)
}
intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- index = (int)spl_offset_convert_to_long(zindex TSRMLS_CC);
- llist = intern->llist;
+ index = spl_offset_convert_to_long(zindex TSRMLS_CC);
+ llist = intern->llist;
- if (index < 0 || index >= intern->llist->count) {
+ if (index < 0 || index >= intern->llist->count) {
zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range", 0 TSRMLS_CC);
return;
}
@@ -1023,12 +1023,11 @@ static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***d
}
/* }}} */
-static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void spl_dllist_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
spl_dllist_it *iterator = (spl_dllist_it *)iter;
- *int_key = (ulong) iterator->traverse_position;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iterator->traverse_position);
}
/* }}} */
@@ -1139,7 +1138,7 @@ SPL_METHOD(SplDoublyLinkedList, serialize)
spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
smart_str buf = {0};
spl_ptr_llist_element *current = intern->llist->head, *next;
- zval *flags;
+ zval *flags;
php_serialize_data_t var_hash;
if (zend_parse_parameters_none() == FAILURE) {
@@ -1235,6 +1234,61 @@ error:
} /* }}} */
+/* {{{ proto void SplDoublyLinkedList::add(mixed $index, mixed $newval) U
+ Inserts a new entry before the specified $index consisting of $newval. */
+SPL_METHOD(SplDoublyLinkedList, add)
+{
+ zval *zindex, *value;
+ spl_dllist_object *intern;
+ spl_ptr_llist_element *element;
+ long index;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
+ return;
+ }
+ SEPARATE_ARG_IF_REF(value);
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ index = spl_offset_convert_to_long(zindex TSRMLS_CC);
+
+ if (index < 0 || index > intern->llist->count) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
+ return;
+ }
+
+ if (index == intern->llist->count) {
+ /* If index is the last entry+1 then we do a push because we're not inserting before any entry */
+ spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
+ } else {
+ /* Create the new element we want to insert */
+ spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
+
+ /* Get the element we want to insert before */
+ element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
+
+ elem->data = value;
+ elem->rc = 1;
+ /* connect to the neighbours */
+ elem->next = element;
+ elem->prev = element->prev;
+
+ /* connect the neighbours to this new element */
+ if (elem->prev == NULL) {
+ intern->llist->head = elem;
+ } else {
+ element->prev->next = elem;
+ }
+ element->prev = elem;
+
+ intern->llist->count++;
+
+ if (intern->llist->ctor) {
+ intern->llist->ctor(elem TSRMLS_CC);
+ }
+ }
+} /* }}} */
+
+
/* iterator handler table */
zend_object_iterator_funcs spl_dllist_it_funcs = {
spl_dllist_it_dtor,
@@ -1322,6 +1376,9 @@ static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = {
SPL_ME(SplDoublyLinkedList, offsetGet, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC)
SPL_ME(SplDoublyLinkedList, offsetSet, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC)
SPL_ME(SplDoublyLinkedList, offsetUnset, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC)
+
+ SPL_ME(SplDoublyLinkedList, add, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC)
+
/* Iterator */
SPL_ME(SplDoublyLinkedList, rewind, arginfo_dllist_void, ZEND_ACC_PUBLIC)
SPL_ME(SplDoublyLinkedList, current, arginfo_dllist_void, ZEND_ACC_PUBLIC)
diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c
index fec7e2c4a..86a5371ed 100644
--- a/ext/spl/spl_fixedarray.c
+++ b/ext/spl/spl_fixedarray.c
@@ -948,18 +948,16 @@ static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval
}
/* }}} */
-static int spl_fixedarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void spl_fixedarray_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
spl_fixedarray_object *intern = iterator->object;
if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
- return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
+ zend_user_it_get_current_key(iter, key TSRMLS_CC);
} else {
- *int_key = (ulong) iterator->object->current;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iterator->object->current);
}
-
}
/* }}} */
diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c
index d2de85b2a..cb1f68dcf 100644
--- a/ext/spl/spl_heap.c
+++ b/ext/spl/spl_heap.c
@@ -949,12 +949,11 @@ static void spl_pqueue_it_get_current_data(zend_object_iterator *iter, zval ***d
}
/* }}} */
-static int spl_heap_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+static void spl_heap_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
{
spl_heap_it *iterator = (spl_heap_it *)iter;
- *int_key = (ulong) iterator->object->heap->count - 1;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iterator->object->heap->count - 1);
}
/* }}} */
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index 87b3763cf..fcb4d20a6 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -190,16 +190,15 @@ static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval *
sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
}
-static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
if (sub_iter->funcs->get_current_key) {
- return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
+ sub_iter->funcs->get_current_key(sub_iter, key TSRMLS_CC);
} else {
- *int_key = iter->index;
- return HASH_KEY_IS_LONG;
+ ZVAL_LONG(key, iter->index);
}
}
@@ -617,20 +616,7 @@ SPL_METHOD(RecursiveIteratorIterator, key)
}
if (iterator->funcs->get_current_key) {
- char *str_key;
- uint str_key_len;
- ulong int_key;
-
- switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
- case HASH_KEY_IS_LONG:
- RETURN_LONG(int_key);
- break;
- case HASH_KEY_IS_STRING:
- RETURN_STRINGL(str_key, str_key_len-1, 0);
- break;
- default:
- RETURN_NULL();
- }
+ iterator->funcs->get_current_key(iterator, return_value TSRMLS_CC);
} else {
RETURN_NULL();
}
@@ -1171,20 +1157,7 @@ SPL_METHOD(RecursiveTreeIterator, key)
}
if (iterator->funcs->get_current_key) {
- char *str_key;
- uint str_key_len;
- ulong int_key;
-
- switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
- case HASH_KEY_IS_LONG:
- ZVAL_LONG(&key, int_key);
- break;
- case HASH_KEY_IS_STRING:
- ZVAL_STRINGL(&key, str_key, str_key_len-1, 0);
- break;
- default:
- ZVAL_NULL(&key);
- }
+ iterator->funcs->get_current_key(iterator, &key TSRMLS_CC);
} else {
ZVAL_NULL(&key);
}
@@ -1590,9 +1563,9 @@ static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
zval_ptr_dtor(&intern->current.data);
intern->current.data = NULL;
}
- if (intern->current.str_key) {
- efree(intern->current.str_key);
- intern->current.str_key = NULL;
+ if (intern->current.key) {
+ zval_ptr_dtor(&intern->current.key);
+ intern->current.key = NULL;
}
if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
if (intern->u.caching.zstr) {
@@ -1635,11 +1608,16 @@ static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more T
intern->current.data = *data;
Z_ADDREF_P(intern->current.data);
}
+
+ MAKE_STD_ZVAL(intern->current.key);
if (intern->inner.iterator->funcs->get_current_key) {
- intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC);
+ intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, intern->current.key TSRMLS_CC);
+ if (EG(exception)) {
+ zval_ptr_dtor(&intern->current.key);
+ intern->current.key = NULL;
+ }
} else {
- intern->current.key_type = HASH_KEY_IS_LONG;
- intern->current.int_key = intern->current.pos;
+ ZVAL_LONG(intern->current.key, intern->current.pos);
}
return EG(exception) ? FAILURE : SUCCESS;
}
@@ -1711,12 +1689,8 @@ SPL_METHOD(dual_it, key)
SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
- if (intern->current.data) {
- if (intern->current.key_type == HASH_KEY_IS_STRING) {
- RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
- } else {
- RETURN_LONG(intern->current.int_key);
- }
+ if (intern->current.key) {
+ RETURN_ZVAL(intern->current.key, 1, 0);
}
RETURN_NULL();
} /* }}} */
@@ -1927,27 +1901,18 @@ SPL_METHOD(CallbackFilterIterator, accept)
zend_fcall_info *fci = &intern->u.cbfilter->fci;
zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc;
zval **params[3];
- zval zkey;
- zval *zkey_p = &zkey;
zval *result;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- if (intern->current.data == NULL) {
+ if (intern->current.data == NULL || intern->current.key == NULL) {
RETURN_FALSE;
}
-
- INIT_PZVAL(&zkey);
- if (intern->current.key_type == HASH_KEY_IS_LONG) {
- ZVAL_LONG(&zkey, intern->current.int_key);
- } else {
- ZVAL_STRINGL(&zkey, intern->current.str_key, intern->current.str_key_len-1, 0);
- }
params[0] = &intern->current.data;
- params[1] = &zkey_p;
+ params[1] = &intern->current.key;
params[2] = &intern->inner.zobject;
fci->retval_ptr_ptr = &result;
@@ -1971,9 +1936,9 @@ SPL_METHOD(CallbackFilterIterator, accept)
SPL_METHOD(RegexIterator, accept)
{
spl_dual_it_object *intern;
- char *subject, tmp[32], *result;
+ char *subject, *result;
int subject_len, use_copy, count = 0, result_len;
- zval subject_copy, zcount, *replacement, tmp_replacement;
+ zval *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement;
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1986,24 +1951,18 @@ SPL_METHOD(RegexIterator, accept)
}
if (intern->u.regex.flags & REGIT_USE_KEY) {
- if (intern->current.key_type == HASH_KEY_IS_LONG) {
- subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
- subject = &tmp[0];
- use_copy = 0;
- } else {
- subject_len = intern->current.str_key_len - 1;
- subject = estrndup(intern->current.str_key, subject_len);
- use_copy = 1;
- }
+ subject_ptr = intern->current.key;
} else {
- zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
- if (use_copy) {
- subject = Z_STRVAL(subject_copy);
- subject_len = Z_STRLEN(subject_copy);
- } else {
- subject = Z_STRVAL_P(intern->current.data);
- subject_len = Z_STRLEN_P(intern->current.data);
- }
+ subject_ptr = intern->current.data;
+ }
+
+ zend_make_printable_zval(subject_ptr, &subject_copy, &use_copy);
+ if (use_copy) {
+ subject = Z_STRVAL(subject_copy);
+ subject_len = Z_STRLEN(subject_copy);
+ } else {
+ subject = Z_STRVAL_P(subject_ptr);
+ subject_len = Z_STRLEN_P(subject_ptr);
}
switch (intern->u.regex.mode)
@@ -2051,12 +2010,9 @@ SPL_METHOD(RegexIterator, accept)
result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
if (intern->u.regex.flags & REGIT_USE_KEY) {
- if (intern->current.key_type != HASH_KEY_IS_LONG) {
- efree(intern->current.str_key);
- }
- intern->current.key_type = HASH_KEY_IS_STRING;
- intern->current.str_key = result;
- intern->current.str_key_len = result_len + 1;
+ zval_ptr_dtor(&intern->current.key);
+ MAKE_STD_ZVAL(intern->current.key);
+ ZVAL_STRINGL(intern->current.key, result, result_len, 0);
} else {
zval_ptr_dtor(&intern->current.data);
MAKE_STD_ZVAL(intern->current.data);
@@ -2590,14 +2546,14 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
/* Full cache ? */
if (intern->u.caching.flags & CIT_FULL_CACHE) {
zval *zcacheval;
+ zval *key = intern->current.key;
MAKE_STD_ZVAL(zcacheval);
ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
- if (intern->current.key_type == HASH_KEY_IS_LONG) {
- add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
- } else {
- zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
- }
+
+ array_set_zval_key(HASH_OF(intern->u.caching.zcache), key, zcacheval);
+
+ zval_ptr_dtor(&zcacheval);
}
/* Recursion ? */
if (intern->dit_type == DIT_RecursiveCachingIterator) {
@@ -2755,13 +2711,9 @@ SPL_METHOD(CachingIterator, __toString)
return;
}
if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
- if (intern->current.key_type == HASH_KEY_IS_STRING) {
- RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
- } else {
- RETVAL_LONG(intern->current.int_key);
- convert_to_string(return_value);
- return;
- }
+ MAKE_COPY_ZVAL(&intern->current.key, return_value);
+ convert_to_string(return_value);
+ return;
} else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
MAKE_COPY_ZVAL(&intern->current.data, return_value);
convert_to_string(return_value);
@@ -3123,19 +3075,7 @@ SPL_METHOD(NoRewindIterator, key)
SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
if (intern->inner.iterator->funcs->get_current_key) {
- char *str_key;
- uint str_key_len;
- ulong int_key;
- switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
- case HASH_KEY_IS_LONG:
- RETURN_LONG(int_key);
- break;
- case HASH_KEY_IS_STRING:
- RETURN_STRINGL(str_key, str_key_len-1, 0);
- break;
- default:
- RETURN_NULL();
- }
+ intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value TSRMLS_CC);
} else {
RETURN_NULL();
}
@@ -3502,11 +3442,7 @@ done:
static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
{
- zval **data, *return_value = (zval*)puser;
- char *str_key;
- uint str_key_len;
- ulong int_key;
- int key_type;
+ zval **data, *return_value = (zval*)puser;
iter->funcs->get_current_data(iter, &data TSRMLS_CC);
if (EG(exception)) {
@@ -3516,20 +3452,13 @@ static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser T
return ZEND_HASH_APPLY_STOP;
}
if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ zval key;
+ iter->funcs->get_current_key(iter, &key TSRMLS_CC);
if (EG(exception)) {
return ZEND_HASH_APPLY_STOP;
}
- Z_ADDREF_PP(data);
- switch(key_type) {
- case HASH_KEY_IS_STRING:
- add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
- efree(str_key);
- break;
- case HASH_KEY_IS_LONG:
- add_index_zval(return_value, int_key, *data);
- break;
- }
+ array_set_zval_key(Z_ARRVAL_P(return_value), &key, *data);
+ zval_dtor(&key);
} else {
Z_ADDREF_PP(data);
add_next_index_zval(return_value, *data);
diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
index 39cc0d133..73d9d2e61 100644
--- a/ext/spl/spl_iterators.h
+++ b/ext/spl/spl_iterators.h
@@ -133,10 +133,7 @@ typedef struct _spl_dual_it_object {
} inner;
struct {
zval *data;
- char *str_key;
- uint str_key_len;
- ulong int_key;
- int key_type; /* HASH_KEY_IS_STRING or HASH_KEY_IS_LONG */
+ zval *key;
int pos;
} current;
dual_it_type dit_type;
diff --git a/ext/spl/tests/SplDoublyLinkedList_add_invalid_offset.phpt b/ext/spl/tests/SplDoublyLinkedList_add_invalid_offset.phpt
new file mode 100644
index 000000000..b94b067f4
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_add_invalid_offset.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that SplDoublyLinkedList::add throws an exception with an invalid offset argument
+--FILE--
+<?php
+try {
+ $dll = new SplDoublyLinkedList();
+ var_dump($dll->add(12,'Offset 12 should not exist'));
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+--EXPECTF--
+Exception: Offset invalid or out of range
diff --git a/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter1.phpt b/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter1.phpt
new file mode 100644
index 000000000..12cfe4000
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter1.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Check that SplDoublyLinkedList::add generate a warning and returns a NULL with missing arguments
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+var_dump($dll->add());
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::add() expects exactly 2 parameters, 0 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter2.phpt b/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter2.phpt
new file mode 100644
index 000000000..c9c319316
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_add_missing_parameter2.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Check that SplDoublyLinkedList::add generate a warning and returns a NULL with a missing value argument
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+var_dump($dll->add(2));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::add() expects exactly 2 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplDoublyLinkedList_add_null_offset.phpt b/ext/spl/tests/SplDoublyLinkedList_add_null_offset.phpt
new file mode 100644
index 000000000..396f89b49
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_add_null_offset.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that SplDoublyLinkedList::add throws an exception with an invalid offset argument
+--FILE--
+<?php
+try {
+ $dll = new SplDoublyLinkedList();
+ var_dump($dll->add(NULL,2));
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+--EXPECTF--
+Exception: Offset invalid or out of range
diff --git a/ext/spl/tests/dllist_013.phpt b/ext/spl/tests/dllist_013.phpt
new file mode 100644
index 000000000..b60f06392
--- /dev/null
+++ b/ext/spl/tests/dllist_013.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: DoublyLinkedList: insert operations
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+// errors
+try {
+ $dll->add(2,5);
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+$dll->add(0,6); // 6
+$dll->add(0,3); // 3 6
+// Insert in the middle of the DLL
+$dll->add(1,4); // 3 4 6
+$dll->add(2,5); // 3 4 5 6
+$dll->unshift(2); // 2 3 5 4 6
+// Insert at the beginning and end of the DLL
+$dll->add(0,1); // 1 2 3 4 5 6
+$dll->add(6,7); // 1 2 3 4 5 6 7
+
+echo count($dll)."\n";
+
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+echo $dll->pop()."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Offset invalid or out of range
+7
+7
+6
+5
+4
+3
+2
+1
+===DONE===
diff --git a/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt
new file mode 100644
index 000000000..4ca9485fa
--- /dev/null
+++ b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Tests iterator_to_array() with non-scalar keys
+--FILE--
+<?php
+
+function gen() {
+ yield "foo" => 0;
+ yield 1 => 1;
+ yield 2.5 => 2;
+ yield null => 3;
+ yield [] => 4;
+ yield new stdClass => 5;
+}
+
+var_dump(iterator_to_array(gen()));
+
+?>
+--EXPECTF--
+Warning: Illegal offset type in %s on line %d
+
+Warning: Illegal offset type in %s on line %d
+array(4) {
+ ["foo"]=>
+ int(0)
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [""]=>
+ int(3)
+}
diff --git a/ext/spl/tests/multiple_iterator_001.phpt b/ext/spl/tests/multiple_iterator_001.phpt
index edd03f504..eb77f7937 100644
--- a/ext/spl/tests/multiple_iterator_001.phpt
+++ b/ext/spl/tests/multiple_iterator_001.phpt
@@ -23,8 +23,8 @@ echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_K
var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC));
-foreach($m as $value) {
- var_dump($m->key(), $value);
+foreach($m as $key => $value) {
+ var_dump($key, $value);
}
try {
$m->current();
@@ -42,8 +42,8 @@ echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUM
$m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC);
var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC));
-foreach($m as $value) {
- var_dump($m->key(), $value);
+foreach($m as $key => $value) {
+ var_dump($key, $value);
}
echo "-- Default flags, added element --\n";
@@ -51,8 +51,8 @@ echo "-- Default flags, added element --\n";
$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC);
$iter2[] = 3;
-foreach($m as $value) {
- var_dump($m->key(), $value);
+foreach($m as $key => $value) {
+ var_dump($key, $value);
}
echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n";
@@ -71,8 +71,8 @@ $m->attachIterator($iter1, "iter1");
$m->attachIterator($iter2, b"iter2");
$m->attachIterator($iter3, 3);
-foreach($m as $value) {
- var_dump($m->key(), $value);
+foreach($m as $key => $value) {
+ var_dump($key, $value);
}
echo "-- Associate with invalid value --\n";
@@ -98,8 +98,8 @@ var_dump($m->containsIterator($iter2));
var_dump($m->detachIterator($iter2));
var_dump($m->countIterators());
var_dump($m->containsIterator($iter2));
-foreach($m as $value) {
- var_dump($m->key(), $value);
+foreach($m as $key => $value) {
+ var_dump($key, $value);
}
?>
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 40a27c053..226bfefc5 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -927,24 +927,12 @@ PHP_FUNCTION(current)
PHP_FUNCTION(key)
{
HashTable *array;
- char *string_key;
- uint string_length;
- ulong num_key;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
return;
}
- switch (zend_hash_get_current_key_ex(array, &string_key, &string_length, &num_key, 0, NULL)) {
- case HASH_KEY_IS_STRING:
- RETVAL_STRINGL(string_key, string_length - 1, 1);
- break;
- case HASH_KEY_IS_LONG:
- RETVAL_LONG(num_key);
- break;
- case HASH_KEY_NON_EXISTANT:
- return;
- }
+ zend_hash_get_current_key_zval(array, return_value);
}
/* }}} */
@@ -1055,9 +1043,6 @@ static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive
zval **args[3], /* Arguments to userland function */
*retval_ptr, /* Return value - unused */
*key=NULL; /* Entry key */
- char *string_key;
- uint string_key_len;
- ulong num_key;
/* Set up known arguments */
args[1] = &key;
@@ -1103,17 +1088,7 @@ static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive
} else {
/* Allocate space for key */
MAKE_STD_ZVAL(key);
-
- /* Set up the key */
- switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_key_len, &num_key, 0, NULL)) {
- case HASH_KEY_IS_LONG:
- Z_TYPE_P(key) = IS_LONG;
- Z_LVAL_P(key) = num_key;
- break;
- case HASH_KEY_IS_STRING:
- ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
- break;
- }
+ zend_hash_get_current_key_zval(target_hash, key);
/* Call the userland function */
if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) {
@@ -1205,9 +1180,6 @@ static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{
res; /* comparison result */
HashPosition pos; /* hash iterator */
zend_bool strict = 0; /* strict comparison or not */
- ulong num_key;
- uint str_key_len;
- char *string_key;
int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {
@@ -1225,15 +1197,8 @@ static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{
if (behavior == 0) {
RETURN_TRUE;
} else {
- /* Return current key */
- switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
- case HASH_KEY_IS_STRING:
- RETURN_STRINGL(string_key, str_key_len - 1, 1);
- break;
- case HASH_KEY_IS_LONG:
- RETURN_LONG(num_key);
- break;
- }
+ zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(array), return_value, &pos);
+ return;
}
}
zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
@@ -2447,9 +2412,6 @@ PHP_FUNCTION(array_keys)
res, /* Result of comparison */
*new_val; /* New value */
int add_key; /* Flag to indicate whether a key should be added */
- char *string_key; /* String key */
- uint string_key_len;
- ulong num_key; /* Numeric key */
zend_bool strict = 0; /* do strict comparison */
HashPosition pos;
int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
@@ -2480,19 +2442,8 @@ PHP_FUNCTION(array_keys)
if (add_key) {
MAKE_STD_ZVAL(new_val);
-
- switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
- case HASH_KEY_IS_STRING:
- ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);
- zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
- break;
-
- case HASH_KEY_IS_LONG:
- Z_TYPE_P(new_val) = IS_LONG;
- Z_LVAL_P(new_val) = num_key;
- zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
- break;
- }
+ zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(input), new_val, &pos);
+ zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
}
zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
@@ -2573,6 +2524,121 @@ PHP_FUNCTION(array_count_values)
}
/* }}} */
+/* {{{ proto array array_column(array input, mixed column_key[, mixed index_key])
+ Return the values from a single column in the input array, identified by the
+ value_key and optionally indexed by the index_key */
+PHP_FUNCTION(array_column)
+{
+ zval *zarray, *zcolumn, *zkey = NULL, **data, **zcolval, **zkeyval;
+ HashTable *arr_hash;
+ HashPosition pointer;
+ ulong column_idx = 0, key_idx = 0;
+ char *column = NULL, *key = NULL, *keyval = NULL;
+ int column_len = 0, key_len = 0, keyval_idx = -1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|z", &zarray, &zcolumn, &zkey) == FAILURE) {
+ return;
+ }
+
+ switch (Z_TYPE_P(zcolumn)) {
+ case IS_NULL:
+ column_idx = 0;
+ break;
+ case IS_LONG:
+ column_idx = Z_LVAL_P(zcolumn);
+ break;
+ case IS_STRING:
+ column = Z_STRVAL_P(zcolumn);
+ column_len = Z_STRLEN_P(zcolumn);
+ break;
+ case IS_OBJECT:
+ convert_to_string(zcolumn);
+ column = Z_STRVAL_P(zcolumn);
+ column_len = Z_STRLEN_P(zcolumn);
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The column key should be either a string or an integer");
+ RETURN_FALSE;
+ }
+
+ if (zkey) {
+ switch (Z_TYPE_P(zkey)) {
+ case IS_NULL:
+ key_idx = 0;
+ break;
+ case IS_LONG:
+ key_idx = Z_LVAL_P(zkey);
+ break;
+ case IS_STRING:
+ key = Z_STRVAL_P(zkey);
+ key_len = Z_STRLEN_P(zkey);
+ break;
+ case IS_OBJECT:
+ convert_to_string(zkey);
+ key = Z_STRVAL_P(zkey);
+ key_len = Z_STRLEN_P(zkey);
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The index key should be either a string or an integer");
+ RETURN_FALSE;
+ }
+ }
+
+ arr_hash = Z_ARRVAL_P(zarray);
+ array_init(return_value);
+
+ for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
+ zend_hash_get_current_data_ex(arr_hash, (void**)&data, &pointer) == SUCCESS;
+ zend_hash_move_forward_ex(arr_hash, &pointer)) {
+
+ if (Z_TYPE_PP(data) == IS_ARRAY) {
+ if (column && zend_hash_find(Z_ARRVAL_PP(data), column, column_len + 1, (void**)&zcolval) == FAILURE) {
+ continue;
+ } else if (!column && zend_hash_index_find(Z_ARRVAL_PP(data), column_idx, (void**)&zcolval) == FAILURE) {
+ continue;
+ }
+
+ Z_ADDREF_PP(zcolval);
+
+ keyval = NULL;
+ keyval_idx = -1;
+
+ if (zkey) {
+ if (key && zend_hash_find(Z_ARRVAL_PP(data), key, key_len + 1, (void**)&zkeyval) == FAILURE) {
+ keyval_idx = -1;
+ } else if (!key && zend_hash_index_find(Z_ARRVAL_PP(data), key_idx, (void**)&zkeyval) == FAILURE) {
+ keyval_idx = -1;
+ } else {
+ switch (Z_TYPE_PP(zkeyval)) {
+ case IS_LONG:
+ keyval_idx = Z_LVAL_PP(zkeyval);
+ break;
+ case IS_STRING:
+ keyval = Z_STRVAL_PP(zkeyval);
+ break;
+ case IS_OBJECT:
+ convert_to_string(*zkeyval);
+ keyval = Z_STRVAL_PP(zkeyval);
+ break;
+ default:
+ keyval_idx = -1;
+ }
+ }
+ }
+
+ if (keyval) {
+ add_assoc_zval(return_value, keyval, *zcolval);
+ } else if (keyval_idx != -1) {
+ add_index_zval(return_value, keyval_idx, *zcolval);
+ } else {
+ add_next_index_zval(return_value, *zcolval);
+ }
+ }
+
+ }
+}
+/* }}} */
+
/* {{{ proto array array_reverse(array input [, bool preserve keys])
Return input as a new array with the order of the entries reversed */
PHP_FUNCTION(array_reverse)
@@ -2691,9 +2757,6 @@ PHP_FUNCTION(array_pad)
PHP_FUNCTION(array_flip)
{
zval *array, **entry, *data;
- char *string_key;
- uint str_key_len;
- ulong num_key;
HashPosition pos;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
@@ -2705,15 +2768,7 @@ PHP_FUNCTION(array_flip)
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
MAKE_STD_ZVAL(data);
- switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 1, &pos)) {
- case HASH_KEY_IS_STRING:
- ZVAL_STRINGL(data, string_key, str_key_len - 1, 0);
- break;
- case HASH_KEY_IS_LONG:
- Z_TYPE_P(data) = IS_LONG;
- Z_LVAL_P(data) = num_key;
- break;
- }
+ zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(array), data, &pos);
if (Z_TYPE_PP(entry) == IS_LONG) {
zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index a40fdd239..3a84d16d6 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -436,6 +436,12 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_count_values, 0)
ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_array_column, 0, 0, 2)
+ ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */
+ ZEND_ARG_INFO(0, column_key)
+ ZEND_ARG_INFO(0, index_key)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_reverse, 0, 0, 1)
ZEND_ARG_INFO(0, input) /* ARRAY_INFO(0, arg, 0) */
ZEND_ARG_INFO(0, preserve_keys)
@@ -3323,6 +3329,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
PHP_FE(array_keys, arginfo_array_keys)
PHP_FE(array_values, arginfo_array_values)
PHP_FE(array_count_values, arginfo_array_count_values)
+ PHP_FE(array_column, arginfo_array_column)
PHP_FE(array_reverse, arginfo_array_reverse)
PHP_FE(array_reduce, arginfo_array_reduce)
PHP_FE(array_pad, arginfo_array_pad)
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index 942c33f9e..1cf277907 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -71,6 +71,7 @@ PHP_FUNCTION(array_replace_recursive);
PHP_FUNCTION(array_keys);
PHP_FUNCTION(array_values);
PHP_FUNCTION(array_count_values);
+PHP_FUNCTION(array_column);
PHP_FUNCTION(array_reverse);
PHP_FUNCTION(array_reduce);
PHP_FUNCTION(array_pad);
diff --git a/ext/standard/tests/array/array_column_basic.phpt b/ext/standard/tests/array/array_column_basic.phpt
new file mode 100644
index 000000000..70ce2136b
--- /dev/null
+++ b/ext/standard/tests/array/array_column_basic.phpt
@@ -0,0 +1,307 @@
+--TEST--
+Test array_column() function: basic functionality
+--FILE--
+<?php
+/* Prototype:
+ * array array_column(array $input, mixed $column_key[, mixed $index_key]);
+ * Description:
+ * Returns an array containing all the values from
+ * the specified "column" in a two-dimensional array.
+ */
+
+echo "*** Testing array_column() : basic functionality ***\n";
+/* Array representing a possible record set returned from a database */
+$records = array(
+ array(
+ 'id' => 1,
+ 'first_name' => 'John',
+ 'last_name' => 'Doe'
+ ),
+ array(
+ 'id' => 2,
+ 'first_name' => 'Sally',
+ 'last_name' => 'Smith'
+ ),
+ array(
+ 'id' => 3,
+ 'first_name' => 'Jane',
+ 'last_name' => 'Jones'
+ )
+);
+
+echo "-- first_name column from recordset --\n";
+var_dump(array_column($records, 'first_name'));
+
+echo "-- id column from recordset --\n";
+var_dump(array_column($records, 'id'));
+
+echo "-- last_name column from recordset, keyed by value from id column --\n";
+var_dump(array_column($records, 'last_name', 'id'));
+
+echo "-- last_name column from recordset, keyed by value from first_name column --\n";
+var_dump(array_column($records, 'last_name', 'first_name'));
+
+echo "\n*** Testing multiple data types ***\n";
+$file = basename(__FILE__);
+$fh = fopen($file, 'r', true);
+$values = array(
+ array(
+ 'id' => 1,
+ 'value' => new stdClass
+ ),
+ array(
+ 'id' => 2,
+ 'value' => 34.2345
+ ),
+ array(
+ 'id' => 3,
+ 'value' => true
+ ),
+ array(
+ 'id' => 4,
+ 'value' => false
+ ),
+ array(
+ 'id' => 5,
+ 'value' => null
+ ),
+ array(
+ 'id' => 6,
+ 'value' => 1234
+ ),
+ array(
+ 'id' => 7,
+ 'value' => 'Foo'
+ ),
+ array(
+ 'id' => 8,
+ 'value' => $fh
+ )
+);
+var_dump(array_column($values, 'value'));
+var_dump(array_column($values, 'value', 'id'));
+
+echo "\n*** Testing numeric column keys ***\n";
+$numericCols = array(
+ array('aaa', '111'),
+ array('bbb', '222'),
+ array('ccc', '333')
+);
+var_dump(array_column($numericCols, 1));
+var_dump(array_column($numericCols, 1, 0));
+
+echo "\n*** Testing failure to find specified column ***\n";
+var_dump(array_column($numericCols, 2));
+var_dump(array_column($numericCols, 'foo'));
+var_dump(array_column($numericCols, 0, 'foo'));
+
+echo "\n*** Testing single dimensional array ***\n";
+$singleDimension = array('foo', 'bar', 'baz');
+var_dump(array_column($singleDimension, 1));
+
+echo "\n*** Testing columns not present in all rows ***\n";
+$mismatchedColumns = array(
+ array('a' => 'foo', 'b' => 'bar', 'e' => 'bbb'),
+ array('a' => 'baz', 'c' => 'qux', 'd' => 'aaa'),
+ array('a' => 'eee', 'b' => 'fff', 'e' => 'ggg'),
+);
+var_dump(array_column($mismatchedColumns, 'c'));
+var_dump(array_column($mismatchedColumns, 'c', 'a'));
+var_dump(array_column($mismatchedColumns, 'a', 'd'));
+var_dump(array_column($mismatchedColumns, 'a', 'e'));
+var_dump(array_column($mismatchedColumns, 'b'));
+var_dump(array_column($mismatchedColumns, 'b', 'a'));
+
+echo "\n*** Testing use of object converted to string ***\n";
+class Foo
+{
+ public function __toString()
+ {
+ return 'last_name';
+ }
+}
+class Bar
+{
+ public function __toString()
+ {
+ return 'first_name';
+ }
+}
+$f = new Foo();
+$b = new Bar();
+var_dump(array_column($records, $f));
+var_dump(array_column($records, $f, $b));
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing array_column() : basic functionality ***
+-- first_name column from recordset --
+array(3) {
+ [0]=>
+ string(4) "John"
+ [1]=>
+ string(5) "Sally"
+ [2]=>
+ string(4) "Jane"
+}
+-- id column from recordset --
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+}
+-- last_name column from recordset, keyed by value from id column --
+array(3) {
+ [1]=>
+ string(3) "Doe"
+ [2]=>
+ string(5) "Smith"
+ [3]=>
+ string(5) "Jones"
+}
+-- last_name column from recordset, keyed by value from first_name column --
+array(3) {
+ ["John"]=>
+ string(3) "Doe"
+ ["Sally"]=>
+ string(5) "Smith"
+ ["Jane"]=>
+ string(5) "Jones"
+}
+
+*** Testing multiple data types ***
+array(8) {
+ [0]=>
+ object(stdClass)#1 (0) {
+ }
+ [1]=>
+ float(34.2345)
+ [2]=>
+ bool(true)
+ [3]=>
+ bool(false)
+ [4]=>
+ NULL
+ [5]=>
+ int(1234)
+ [6]=>
+ string(3) "Foo"
+ [7]=>
+ resource(5) of type (stream)
+}
+array(8) {
+ [1]=>
+ object(stdClass)#1 (0) {
+ }
+ [2]=>
+ float(34.2345)
+ [3]=>
+ bool(true)
+ [4]=>
+ bool(false)
+ [5]=>
+ NULL
+ [6]=>
+ int(1234)
+ [7]=>
+ string(3) "Foo"
+ [8]=>
+ resource(5) of type (stream)
+}
+
+*** Testing numeric column keys ***
+array(3) {
+ [0]=>
+ string(3) "111"
+ [1]=>
+ string(3) "222"
+ [2]=>
+ string(3) "333"
+}
+array(3) {
+ ["aaa"]=>
+ string(3) "111"
+ ["bbb"]=>
+ string(3) "222"
+ ["ccc"]=>
+ string(3) "333"
+}
+
+*** Testing failure to find specified column ***
+array(0) {
+}
+array(0) {
+}
+array(3) {
+ [0]=>
+ string(3) "aaa"
+ [1]=>
+ string(3) "bbb"
+ [2]=>
+ string(3) "ccc"
+}
+
+*** Testing single dimensional array ***
+array(0) {
+}
+
+*** Testing columns not present in all rows ***
+array(1) {
+ [0]=>
+ string(3) "qux"
+}
+array(1) {
+ ["baz"]=>
+ string(3) "qux"
+}
+array(3) {
+ [0]=>
+ string(3) "foo"
+ ["aaa"]=>
+ string(3) "baz"
+ [1]=>
+ string(3) "eee"
+}
+array(3) {
+ ["bbb"]=>
+ string(3) "foo"
+ [0]=>
+ string(3) "baz"
+ ["ggg"]=>
+ string(3) "eee"
+}
+array(2) {
+ [0]=>
+ string(3) "bar"
+ [1]=>
+ string(3) "fff"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "bar"
+ ["eee"]=>
+ string(3) "fff"
+}
+
+*** Testing use of object converted to string ***
+array(3) {
+ [0]=>
+ string(3) "Doe"
+ [1]=>
+ string(5) "Smith"
+ [2]=>
+ string(5) "Jones"
+}
+array(3) {
+ ["John"]=>
+ string(3) "Doe"
+ ["Sally"]=>
+ string(5) "Smith"
+ ["Jane"]=>
+ string(5) "Jones"
+}
+Done
diff --git a/ext/standard/tests/array/array_column_error.phpt b/ext/standard/tests/array/array_column_error.phpt
new file mode 100644
index 000000000..1aec1acc6
--- /dev/null
+++ b/ext/standard/tests/array/array_column_error.phpt
@@ -0,0 +1,98 @@
+--TEST--
+Test array_column() function: error conditions
+--FILE--
+<?php
+/* Prototype:
+ * array array_column(array $input, mixed $column_key[, mixed $index_key]);
+ * Description:
+ * Returns an array containing all the values from
+ * the specified "column" in a two-dimensional array.
+ */
+
+echo "*** Testing array_column() : error conditions ***\n";
+
+echo "\n-- Testing array_column() function with Zero arguments --\n";
+var_dump(array_column());
+
+echo "\n-- Testing array_column() function with One argument --\n";
+var_dump(array_column(array()));
+
+echo "\n-- Testing array_column() function with string as first parameter --\n";
+var_dump(array_column('foo', 0));
+
+echo "\n-- Testing array_column() function with int as first parameter --\n";
+var_dump(array_column(1, 'foo'));
+
+echo "\n-- Testing array_column() column key parameter should be a string or an integer (testing bool) --\n";
+var_dump(array_column(array(), true));
+
+echo "\n-- Testing array_column() column key parameter should be a string or integer (testing float) --\n";
+var_dump(array_column(array(), 2.3));
+
+echo "\n-- Testing array_column() column key parameter should be a string or integer (testing array) --\n";
+var_dump(array_column(array(), array()));
+
+echo "\n-- Testing array_column() index key parameter should be a string or an integer (testing bool) --\n";
+var_dump(array_column(array(), 'foo', true));
+
+echo "\n-- Testing array_column() index key parameter should be a string or integer (testing float) --\n";
+var_dump(array_column(array(), 'foo', 2.3));
+
+echo "\n-- Testing array_column() index key parameter should be a string or integer (testing array) --\n";
+var_dump(array_column(array(), 'foo', array()));
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing array_column() : error conditions ***
+
+-- Testing array_column() function with Zero arguments --
+
+Warning: array_column() expects at least 2 parameters, 0 given in %s on line %d
+NULL
+
+-- Testing array_column() function with One argument --
+
+Warning: array_column() expects at least 2 parameters, 1 given in %s on line %d
+NULL
+
+-- Testing array_column() function with string as first parameter --
+
+Warning: array_column() expects parameter 1 to be array, string given in %s on line %d
+NULL
+
+-- Testing array_column() function with int as first parameter --
+
+Warning: array_column() expects parameter 1 to be array, integer given in %s on line %d
+NULL
+
+-- Testing array_column() column key parameter should be a string or an integer (testing bool) --
+
+Warning: array_column(): The column key should be either a string or an integer in %s on line %d
+bool(false)
+
+-- Testing array_column() column key parameter should be a string or integer (testing float) --
+
+Warning: array_column(): The column key should be either a string or an integer in %s on line %d
+bool(false)
+
+-- Testing array_column() column key parameter should be a string or integer (testing array) --
+
+Warning: array_column(): The column key should be either a string or an integer in %s on line %d
+bool(false)
+
+-- Testing array_column() index key parameter should be a string or an integer (testing bool) --
+
+Warning: array_column(): The index key should be either a string or an integer in %s on line %d
+bool(false)
+
+-- Testing array_column() index key parameter should be a string or integer (testing float) --
+
+Warning: array_column(): The index key should be either a string or an integer in %s on line %d
+bool(false)
+
+-- Testing array_column() index key parameter should be a string or integer (testing array) --
+
+Warning: array_column(): The index key should be either a string or an integer in %s on line %d
+bool(false)
+Done
diff --git a/ext/standard/tests/array/uasort_variation9.phpt b/ext/standard/tests/array/uasort_variation9.phpt
index 486042e5e..85578b020 100644
--- a/ext/standard/tests/array/uasort_variation9.phpt
+++ b/ext/standard/tests/array/uasort_variation9.phpt
@@ -14,7 +14,7 @@ echo "*** Testing uasort() : 'cmp_function' with reference arguments ***\n";
// comparison function
/* Prototype : int cmp(mixed &$value1, mixed &$value2)
- * Parameters : $value1 and $value2 - values recieved by reference
+ * Parameters : $value1 and $value2 - values received by reference
* Return value : 0 - if both values are same
* 1 - if value1 is greater than value2
* -1 - if value1 is less than value2
diff --git a/ext/standard/tests/bug64370_var1.phpt b/ext/standard/tests/bug64370_var1.phpt
new file mode 100644
index 000000000..aca46a594
--- /dev/null
+++ b/ext/standard/tests/bug64370_var1.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Test bug #64370 microtime(true) less than $_SERVER['REQUEST_TIME_FLOAT']
+--FILE--
+<?php
+echo "\$_SERVER['REQUEST_TIME']: {$_SERVER['REQUEST_TIME']}\n";
+echo "\$_SERVER['REQUEST_TIME_FLOAT']: {$_SERVER['REQUEST_TIME_FLOAT']}\n";
+echo "time(): " . time() . "\n";
+echo "microtime(true): " . microtime(true) . "\n";
+$d = (microtime(true)-$_SERVER['REQUEST_TIME_FLOAT'])*1000;
+echo "created in $d ms\n";
+echo ((bool)($d >= 0)) . "\n";
+?>
+===DONE===
+--EXPECTF--
+$_SERVER['REQUEST_TIME']: %d
+$_SERVER['REQUEST_TIME_FLOAT']: %f
+time(): %d
+microtime(true): %f
+created in %f ms
+1
+===DONE===
diff --git a/ext/standard/tests/bug64370_var2.phpt b/ext/standard/tests/bug64370_var2.phpt
new file mode 100644
index 000000000..d0d3590ea
--- /dev/null
+++ b/ext/standard/tests/bug64370_var2.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Test bug #64370 sequential microtime(true) calls
+--FILE--
+<?php
+
+$i = 0;
+while(100000 > $i++) {
+ $m0 = microtime(true);
+ $m1 = microtime(true);
+ $d = $m1 - $m0;
+
+ /*echo "$d\n";*/
+
+ if ($d < 0) {
+ die("failed in {$i}th iteration");
+ }
+}
+echo "ok\n";
+?>
+===DONE===
+--EXPECT--
+ok
+===DONE===
diff --git a/ext/standard/tests/serialize/bug64354_1.phpt b/ext/standard/tests/serialize/bug64354_1.phpt
new file mode 100644
index 000000000..e85749bcb
--- /dev/null
+++ b/ext/standard/tests/serialize/bug64354_1.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+spl_autoload_register(
+ function($class) {
+ throw new Exception("Failed");
+ }
+);
+
+try {
+ var_dump(unserialize('O:1:"A":0:{}'));
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+try {
+ var_dump(unserialize('a:2:{i:0;O:1:"A":0:{}i:1;O:1:"A":0:{}}'));
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
+string(6) "Failed"
diff --git a/ext/standard/tests/serialize/bug64354_2.phpt b/ext/standard/tests/serialize/bug64354_2.phpt
new file mode 100644
index 000000000..41a455b54
--- /dev/null
+++ b/ext/standard/tests/serialize/bug64354_2.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+class A {
+ public function __wakeup() {
+ throw new Exception("Failed");
+ }
+}
+
+spl_autoload_register(
+ function($class) {
+ throw new Exception("Failed");
+ }
+);
+
+try {
+ var_dump(unserialize('a:2:{i:0;O:1:"A":0:{}i:1;O:1:"B":0:{}}'));
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
diff --git a/ext/standard/tests/serialize/bug64354_3.phpt b/ext/standard/tests/serialize/bug64354_3.phpt
new file mode 100644
index 000000000..3ce61152d
--- /dev/null
+++ b/ext/standard/tests/serialize/bug64354_3.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+class A {
+ public function __sleep() {
+ throw new Exception("Failed");
+ }
+}
+
+class B implements Serializable {
+ public function serialize() {
+ return NULL;
+ }
+
+ public function unserialize($data) {
+ }
+}
+
+$data = array(new A, new B);
+
+try {
+ serialize($data);
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
diff --git a/ext/standard/var.c b/ext/standard/var.c
index b13edf661..f76a14cfa 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -714,6 +714,10 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var
ulong *var_already;
HashTable *myht;
+ if (EG(exception)) {
+ return;
+ }
+
if (var_hash && php_add_var_hash(var_hash, struc, (void *) &var_already TSRMLS_CC) == FAILURE) {
if (Z_ISREF_P(struc)) {
smart_str_appendl(buf, "R:", 2);
@@ -800,8 +804,15 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var
BG(serialize_lock)++;
res = call_user_function_ex(CG(function_table), &struc, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
BG(serialize_lock)--;
+
+ if (EG(exception)) {
+ if (retval_ptr) {
+ zval_ptr_dtor(&retval_ptr);
+ }
+ return;
+ }
- if (res == SUCCESS && !EG(exception)) {
+ if (res == SUCCESS) {
if (retval_ptr) {
if (HASH_OF(retval_ptr)) {
php_var_serialize_class(buf, struc, retval_ptr, var_hash TSRMLS_CC);
@@ -921,6 +932,11 @@ PHP_FUNCTION(serialize)
php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(var_hash);
+ if (EG(exception)) {
+ smart_str_free(&buf);
+ RETURN_FALSE;
+ }
+
if (buf.c) {
RETURN_STRINGL(buf.c, buf.len, 0);
} else {
@@ -951,7 +967,9 @@ PHP_FUNCTION(unserialize)
if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) {
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
zval_dtor(return_value);
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ if (!EG(exception)) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ }
RETURN_FALSE;
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 03cf8dc60..2e8b6f62b 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Mon Jan 21 11:41:53 2013 */
+/* Generated by re2c 0.13.5 */
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
@@ -394,8 +394,13 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
BG(serialize_lock)--;
}
- if (retval_ptr)
+ if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
+ }
+
+ if (EG(exception)) {
+ return 0;
+ }
return finish_nested_data(UNSERIALIZE_PASSTHRU);
@@ -615,10 +620,19 @@ yy20:
BG(serialize_lock) = 1;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
BG(serialize_lock) = 0;
+ if (EG(exception)) {
+ efree(class_name);
+ return 0;
+ }
ce = *pce;
break;
}
BG(serialize_lock) = 0;
+
+ if (EG(exception)) {
+ efree(class_name);
+ return 0;
+ }
/* Check for unserialize callback */
if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
@@ -636,6 +650,12 @@ yy20:
BG(serialize_lock) = 1;
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
BG(serialize_lock) = 0;
+ if (EG(exception)) {
+ efree(class_name);
+ zval_ptr_dtor(&user_func);
+ zval_ptr_dtor(&arg_func_name);
+ return 0;
+ }
php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
incomplete_class = 1;
ce = PHP_IC_ENTRY;
@@ -647,6 +667,12 @@ yy20:
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
+ if (EG(exception)) {
+ efree(class_name);
+ zval_ptr_dtor(&user_func);
+ zval_ptr_dtor(&arg_func_name);
+ return 0;
+ }
/* The callback function may have defined the class */
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 204995783..4d99cbfd7 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -400,8 +400,13 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
BG(serialize_lock)--;
}
- if (retval_ptr)
+ if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
+ }
+
+ if (EG(exception)) {
+ return 0;
+ }
return finish_nested_data(UNSERIALIZE_PASSTHRU);
@@ -681,10 +686,19 @@ object ":" uiv ":" ["] {
BG(serialize_lock) = 1;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
BG(serialize_lock) = 0;
+ if (EG(exception)) {
+ efree(class_name);
+ return 0;
+ }
ce = *pce;
break;
}
BG(serialize_lock) = 0;
+
+ if (EG(exception)) {
+ efree(class_name);
+ return 0;
+ }
/* Check for unserialize callback */
if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
@@ -702,6 +716,12 @@ object ":" uiv ":" ["] {
BG(serialize_lock) = 1;
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
BG(serialize_lock) = 0;
+ if (EG(exception)) {
+ efree(class_name);
+ zval_ptr_dtor(&user_func);
+ zval_ptr_dtor(&arg_func_name);
+ return 0;
+ }
php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
incomplete_class = 1;
ce = PHP_IC_ENTRY;
@@ -713,6 +733,12 @@ object ":" uiv ":" ["] {
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
+ if (EG(exception)) {
+ efree(class_name);
+ zval_ptr_dtor(&user_func);
+ zval_ptr_dtor(&arg_func_name);
+ return 0;
+ }
/* The callback function may have defined the class */
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
diff --git a/ext/zip/lib/zip_close.c b/ext/zip/lib/zip_close.c
index 362f92d74..e66c56697 100644
--- a/ext/zip/lib/zip_close.c
+++ b/ext/zip/lib/zip_close.c
@@ -88,6 +88,9 @@ zip_close(struct zip *za)
if (za == NULL)
return -1;
+ if (za->zp == NULL)
+ return -1;
+
if (!_zip_changed(za, &survivors)) {
_zip_free(za);
return 0;
@@ -164,9 +167,10 @@ zip_close(struct zip *za)
for (j=0; j<survivors; j++) {
i = filelist[j].idx;
+ _zip_dirent_init(&de);
+
/* create new local directory entry */
if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) {
- _zip_dirent_init(&de);
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
_zip_dirent_torrent_normalize(&de);
diff --git a/ext/zip/lib/zip_dirent.c b/ext/zip/lib/zip_dirent.c
index b5b9d273b..b9dac5c98 100644
--- a/ext/zip/lib/zip_dirent.c
+++ b/ext/zip/lib/zip_dirent.c
@@ -157,11 +157,17 @@ _zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
void
_zip_dirent_finalize(struct zip_dirent *zde)
{
- free(zde->filename);
+ if (zde->filename_len > 0) {
+ free(zde->filename);
+ }
zde->filename = NULL;
- free(zde->extrafield);
+ if (zde->extrafield_len > 0) {
+ free(zde->extrafield);
+ }
zde->extrafield = NULL;
- free(zde->comment);
+ if (zde->comment_len > 0) {
+ free(zde->comment);
+ }
zde->comment = NULL;
}
diff --git a/generated_lists b/generated_lists
index 4d149666f..862cc3232 100644
--- a/generated_lists
+++ b/generated_lists
@@ -1,2 +1,2 @@
makefile_am_files = Zend/Makefile.am TSRM/Makefile.am
-config_m4_files = Zend/Zend.m4 TSRM/tsrm.m4 TSRM/threads.m4 Zend/acinclude.m4 ext/bcmath/config.m4 ext/bz2/config.m4 ext/calendar/config.m4 ext/ctype/config.m4 ext/curl/config.m4 ext/date/config0.m4 ext/dba/config.m4 ext/dom/config.m4 ext/enchant/config.m4 ext/ereg/config0.m4 ext/exif/config.m4 ext/fileinfo/config.m4 ext/filter/config.m4 ext/ftp/config.m4 ext/gd/config.m4 ext/gettext/config.m4 ext/gmp/config.m4 ext/hash/config.m4 ext/iconv/config.m4 ext/imap/config.m4 ext/interbase/config.m4 ext/intl/config.m4 ext/json/config.m4 ext/ldap/config.m4 ext/libxml/config0.m4 ext/mbstring/config.m4 ext/mcrypt/config.m4 ext/mssql/config.m4 ext/mysql/config.m4 ext/mysqli/config.m4 ext/mysqlnd/config9.m4 ext/oci8/config.m4 ext/odbc/config.m4 ext/openssl/config0.m4 ext/pcntl/config.m4 ext/pcre/config0.m4 ext/pdo/config.m4 ext/pdo_dblib/config.m4 ext/pdo_firebird/config.m4 ext/pdo_mysql/config.m4 ext/pdo_oci/config.m4 ext/pdo_odbc/config.m4 ext/pdo_pgsql/config.m4 ext/pdo_sqlite/config.m4 ext/pgsql/config.m4 ext/phar/config.m4 ext/posix/config.m4 ext/pspell/config.m4 ext/readline/config.m4 ext/recode/config9.m4 ext/recode/config.m4 ext/reflection/config.m4 ext/session/config.m4 ext/shmop/config.m4 ext/simplexml/config.m4 ext/snmp/config.m4 ext/soap/config.m4 ext/sockets/config.m4 ext/spl/config.m4 ext/sqlite3/config0.m4 ext/standard/config.m4 ext/sybase_ct/config.m4 ext/sysvmsg/config.m4 ext/sysvsem/config.m4 ext/sysvshm/config.m4 ext/tidy/config.m4 ext/tokenizer/config.m4 ext/wddx/config.m4 ext/xml/config.m4 ext/xmlreader/config.m4 ext/xmlrpc/config.m4 ext/xmlwriter/config.m4 ext/xsl/config.m4 ext/zip/config.m4 ext/zlib/config0.m4 sapi/aolserver/config.m4 sapi/apache2filter/config.m4 sapi/apache2handler/config.m4 sapi/apache/config.m4 sapi/apache_hooks/config.m4 sapi/caudium/config.m4 sapi/cli/config.m4 sapi/continuity/config.m4 sapi/embed/config.m4 sapi/fpm/config.m4 sapi/isapi/config.m4 sapi/litespeed/config.m4 sapi/milter/config.m4 sapi/nsapi/config.m4 sapi/phttpd/config.m4 sapi/pi3web/config.m4 sapi/roxen/config.m4 sapi/thttpd/config.m4 sapi/tux/config.m4 sapi/webjames/config.m4
+config_m4_files = Zend/Zend.m4 TSRM/tsrm.m4 TSRM/threads.m4 Zend/acinclude.m4 ext/bcmath/config.m4 ext/bz2/config.m4 ext/calendar/config.m4 ext/ctype/config.m4 ext/curl/config.m4 ext/date/config0.m4 ext/dba/config.m4 ext/dom/config.m4 ext/enchant/config.m4 ext/ereg/config0.m4 ext/exif/config.m4 ext/fileinfo/config.m4 ext/filter/config.m4 ext/ftp/config.m4 ext/gd/config.m4 ext/gettext/config.m4 ext/gmp/config.m4 ext/hash/config.m4 ext/iconv/config.m4 ext/imap/config.m4 ext/interbase/config.m4 ext/intl/config.m4 ext/json/config.m4 ext/ldap/config.m4 ext/libxml/config0.m4 ext/mbstring/config.m4 ext/mcrypt/config.m4 ext/mssql/config.m4 ext/mysql/config.m4 ext/mysqli/config.m4 ext/mysqlnd/config9.m4 ext/oci8/config.m4 ext/odbc/config.m4 ext/opcache/config.m4 ext/openssl/config0.m4 ext/pcntl/config.m4 ext/pcre/config0.m4 ext/pdo/config.m4 ext/pdo_dblib/config.m4 ext/pdo_firebird/config.m4 ext/pdo_mysql/config.m4 ext/pdo_oci/config.m4 ext/pdo_odbc/config.m4 ext/pdo_pgsql/config.m4 ext/pdo_sqlite/config.m4 ext/pgsql/config.m4 ext/phar/config.m4 ext/posix/config.m4 ext/pspell/config.m4 ext/readline/config.m4 ext/recode/config9.m4 ext/recode/config.m4 ext/reflection/config.m4 ext/session/config.m4 ext/shmop/config.m4 ext/simplexml/config.m4 ext/snmp/config.m4 ext/soap/config.m4 ext/sockets/config.m4 ext/spl/config.m4 ext/sqlite3/config0.m4 ext/standard/config.m4 ext/sybase_ct/config.m4 ext/sysvmsg/config.m4 ext/sysvsem/config.m4 ext/sysvshm/config.m4 ext/tidy/config.m4 ext/tokenizer/config.m4 ext/wddx/config.m4 ext/xml/config.m4 ext/xmlreader/config.m4 ext/xmlrpc/config.m4 ext/xmlwriter/config.m4 ext/xsl/config.m4 ext/zip/config.m4 ext/zlib/config0.m4 sapi/aolserver/config.m4 sapi/apache2filter/config.m4 sapi/apache2handler/config.m4 sapi/apache/config.m4 sapi/apache_hooks/config.m4 sapi/caudium/config.m4 sapi/cli/config.m4 sapi/continuity/config.m4 sapi/embed/config.m4 sapi/fpm/config.m4 sapi/isapi/config.m4 sapi/litespeed/config.m4 sapi/milter/config.m4 sapi/nsapi/config.m4 sapi/phttpd/config.m4 sapi/pi3web/config.m4 sapi/roxen/config.m4 sapi/thttpd/config.m4 sapi/tux/config.m4 sapi/webjames/config.m4
diff --git a/main/network.c b/main/network.c
index 88e166311..5c0404b23 100644
--- a/main/network.c
+++ b/main/network.c
@@ -872,7 +872,7 @@ skip_bind:
efree(local_address);
}
}
- /* free error string recieved during previous iteration (if any) */
+ /* free error string received during previous iteration (if any) */
if (error_string && *error_string) {
efree(*error_string);
*error_string = NULL;
diff --git a/main/php_config.h.in b/main/php_config.h.in
index 8cb230f2f..6e76a4abf 100644
--- a/main/php_config.h.in
+++ b/main/php_config.h.in
@@ -132,6 +132,9 @@
/* Whether to build odbc as dynamic module */
#undef COMPILE_DL_ODBC
+/* Whether to build opcache as dynamic module */
+#undef COMPILE_DL_OPCACHE
+
/* Whether to build openssl as dynamic module */
#undef COMPILE_DL_OPENSSL
@@ -1195,6 +1198,9 @@
/* Define to 1 if you have the <monetary.h> header file. */
#undef HAVE_MONETARY_H
+/* Define if you have mprotect() function */
+#undef HAVE_MPROTECT
+
/* Define to 1 if you have the `mremap' function. */
#undef HAVE_MREMAP
@@ -1435,6 +1441,9 @@
/* */
#undef HAVE_PSPELL
+/* Define to 1 if the PS_STRINGS thing exists. */
+#undef HAVE_PS_STRINGS
+
/* do we have ptrace? */
#undef HAVE_PTRACE
@@ -1543,6 +1552,21 @@
/* */
#undef HAVE_SHMOP
+/* Define if you have SysV IPC SHM support */
+#undef HAVE_SHM_IPC
+
+/* Define if you have mmap(MAP_ANON) SHM support */
+#undef HAVE_SHM_MMAP_ANON
+
+/* Define if you have mmap() SHM support */
+#undef HAVE_SHM_MMAP_FILE
+
+/* Define if you have POSIX mmap() SHM support */
+#undef HAVE_SHM_MMAP_POSIX
+
+/* Define if you have mmap("/dev/zero") SHM support */
+#undef HAVE_SHM_MMAP_ZERO
+
/* Define to 1 if you have the `shutdown' function. */
#undef HAVE_SHUTDOWN
@@ -1842,6 +1866,9 @@
/* Define to 1 if you have the <sys/poll.h> header file. */
#undef HAVE_SYS_POLL_H
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+#undef HAVE_SYS_PSTAT_H
+
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
diff --git a/main/php_ini.c b/main/php_ini.c
index b15a3846d..cb2c7ea80 100644
--- a/main/php_ini.c
+++ b/main/php_ini.c
@@ -290,7 +290,7 @@ static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_t
is_special_section = 1;
has_per_dir_config = 1;
- /* make the path lowercase on Windows, for case insensitivty. Does nothign for other platforms */
+ /* make the path lowercase on Windows, for case insensitivity. Does nothing for other platforms */
TRANSLATE_SLASHES_LOWER(key);
/* HOST sections */
@@ -357,7 +357,24 @@ static void php_load_php_extension_cb(void *arg TSRMLS_DC)
*/
static void php_load_zend_extension_cb(void *arg TSRMLS_DC)
{
- zend_load_extension(*((char **) arg));
+ char *filename = *((char **) arg);
+ int length = strlen(filename);
+
+ if (IS_ABSOLUTE_PATH(filename, length)) {
+ zend_load_extension(filename);
+ } else {
+ char *libpath;
+ char *extension_dir = INI_STR("extension_dir");
+ int extension_dir_len = strlen(extension_dir);
+
+ if (IS_SLASH(extension_dir[extension_dir_len-1])) {
+ spprintf(&libpath, 0, "%s%s", extension_dir, filename);
+ } else {
+ spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename);
+ }
+ zend_load_extension(libpath);
+ efree(libpath);
+ }
}
/* }}} */
diff --git a/main/php_version.h b/main/php_version.h
index 7a57019aa..61c507b32 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -3,6 +3,6 @@
#define PHP_MAJOR_VERSION 5
#define PHP_MINOR_VERSION 5
#define PHP_RELEASE_VERSION 0
-#define PHP_EXTRA_VERSION "alpha6"
-#define PHP_VERSION "5.5.0alpha6"
+#define PHP_EXTRA_VERSION "beta1"
+#define PHP_VERSION "5.5.0beta1"
#define PHP_VERSION_ID 50500
diff --git a/run-tests.php b/run-tests.php
index 8b7fa7f8b..84907a705 100755
--- a/run-tests.php
+++ b/run-tests.php
@@ -240,6 +240,7 @@ $ini_overwrites = array(
'ignore_repeated_errors=0',
'precision=14',
'memory_limit=128M',
+ 'opcache.fast_shutdown=0',
);
function write_information($show_html)
diff --git a/sapi/cli/config.m4 b/sapi/cli/config.m4
index cdfa1f7da..9a1b98da4 100644
--- a/sapi/cli/config.m4
+++ b/sapi/cli/config.m4
@@ -6,6 +6,23 @@ PHP_ARG_ENABLE(cli,,
[ --disable-cli Disable building CLI version of PHP
(this forces --without-pear)], yes, no)
+AC_CHECK_FUNCS(setproctitle)
+
+AC_CHECK_HEADERS([sys/pstat.h])
+
+AC_CACHE_CHECK([for PS_STRINGS], [cli_cv_var_PS_STRINGS],
+[AC_TRY_LINK(
+[#include <machine/vmparam.h>
+#include <sys/exec.h>
+],
+[PS_STRINGS->ps_nargvstr = 1;
+PS_STRINGS->ps_argvstr = "foo";],
+[cli_cv_var_PS_STRINGS=yes],
+[cli_cv_var_PS_STRINGS=no])])
+if test "$cli_cv_var_PS_STRINGS" = yes ; then
+ AC_DEFINE([HAVE_PS_STRINGS], [], [Define to 1 if the PS_STRINGS thing exists.])
+fi
+
AC_MSG_CHECKING(for CLI build)
if test "$PHP_CLI" != "no"; then
PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/cli/Makefile.frag)
@@ -14,7 +31,7 @@ if test "$PHP_CLI" != "no"; then
SAPI_CLI_PATH=sapi/cli/php
dnl Select SAPI
- PHP_SELECT_SAPI(cli, program, php_cli.c php_http_parser.c php_cli_server.c,, '$(SAPI_CLI_PATH)')
+ PHP_SELECT_SAPI(cli, program, php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c,, '$(SAPI_CLI_PATH)')
case $host_alias in
*aix*)
diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32
index 4d0dad58e..adcbb2b49 100644
--- a/sapi/cli/config.w32
+++ b/sapi/cli/config.w32
@@ -6,7 +6,7 @@ ARG_ENABLE('crt-debug', 'Enable CRT memory dumps for debugging sent to STDERR',
ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no');
if (PHP_CLI == "yes") {
- SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c', 'php.exe');
+ SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c php_cli_process_title.c ps_title.c', 'php.exe');
ADD_FLAG("LIBS_CLI", "ws2_32.lib");
if (PHP_CRT_DEBUG == "yes") {
ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP");
@@ -15,7 +15,7 @@ if (PHP_CLI == "yes") {
}
if (PHP_CLI_WIN32 == "yes") {
- SAPI('cli_win32', 'cli_win32.c', 'php-win.exe');
+ SAPI('cli_win32', 'cli_win32.c php_cli_process_title.c ps_title.c', 'php-win.exe');
ADD_FLAG("LDFLAGS_CLI_WIN32", "/stack:8388608");
}
diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c
index c01f3705b..4b8bae7f7 100644
--- a/sapi/cli/php_cli.c
+++ b/sapi/cli/php_cli.c
@@ -86,6 +86,9 @@
#include "php_cli_server.h"
#endif
+#include "ps_title.h"
+#include "php_cli_process_title.h"
+
#ifndef PHP_WIN32
# define php_select(m, r, w, e, t) select(m, r, w, e, t)
#else
@@ -478,6 +481,8 @@ ZEND_END_ARG_INFO()
static const zend_function_entry additional_functions[] = {
ZEND_FE(dl, arginfo_dl)
+ PHP_FE(cli_set_process_title, arginfo_cli_set_process_title)
+ PHP_FE(cli_get_process_title, arginfo_cli_get_process_title)
{NULL, NULL, NULL}
};
@@ -1200,6 +1205,7 @@ int main(int argc, char *argv[])
int argc = __argc;
char **argv = __argv;
#endif
+
int c;
int exit_status = SUCCESS;
int module_started = 0, sapi_started = 0;
@@ -1211,6 +1217,12 @@ int main(int argc, char *argv[])
int ini_ignore = 0;
sapi_module_struct *sapi_module = &cli_sapi_module;
+ /*
+ * Do not move this initialization. It needs to happen before argv is used
+ * in any way.
+ */
+ argv = save_ps_args(argc, argv);
+
cli_sapi_module.additional_functions = additional_functions;
#if defined(PHP_WIN32) && defined(_DEBUG) && defined(PHP_WIN32_DEBUG_HEAP)
@@ -1299,6 +1311,7 @@ int main(int argc, char *argv[])
#ifndef PHP_CLI_WIN32_NO_CONSOLE
case 'S':
sapi_module = &cli_server_sapi_module;
+ cli_server_sapi_module.additional_functions = server_additional_functions;
break;
#endif
case 'h': /* help & quit */
@@ -1385,6 +1398,11 @@ out:
tsrm_shutdown();
#endif
+ /*
+ * Do not move this de-initialization. It needs to happen right before
+ * exiting.
+ */
+ cleanup_ps_args(argv);
exit(exit_status);
}
/* }}} */
diff --git a/sapi/cli/php_cli_process_title.c b/sapi/cli/php_cli_process_title.c
new file mode 100644
index 000000000..c50c412b1
--- /dev/null
+++ b/sapi/cli/php_cli_process_title.c
@@ -0,0 +1,80 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 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: |
+ | http://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: Keyur Govande (kgovande@gmail.com) |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_cli_process_title.h"
+#include "ps_title.h"
+
+/* {{{ proto boolean cli_set_process_title(string arg)
+ Return a boolean to confirm if the process title was successfully changed or not */
+PHP_FUNCTION(cli_set_process_title)
+{
+ char *title = NULL;
+ int title_len;
+ int rc;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &title, &title_len) == FAILURE) {
+ return;
+ }
+
+ rc = set_ps_title(title);
+ if (rc == PS_TITLE_SUCCESS) {
+ RETURN_TRUE;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cli_set_process_title had an error: %s", ps_title_errno(rc));
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string cli_get_process_title()
+ Return a string with the current process title. NULL if error. */
+PHP_FUNCTION(cli_get_process_title)
+{
+ int length = 0;
+ const char* title = NULL;
+ int rc;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ rc = get_ps_title(&length, &title);
+ if (rc != PS_TITLE_SUCCESS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cli_get_process_title had an error: %s", ps_title_errno(rc));
+ RETURN_NULL();
+ }
+
+ RETURN_STRINGL(title, length, 1);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/sapi/cli/php_cli_process_title.h b/sapi/cli/php_cli_process_title.h
new file mode 100644
index 000000000..b4b0861a2
--- /dev/null
+++ b/sapi/cli/php_cli_process_title.h
@@ -0,0 +1,43 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 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: |
+ | http://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: Keyur Govande (kgovande@gmail.com) |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PS_TITLE_HEADER
+#define PHP_PS_TITLE_HEADER
+
+ZEND_BEGIN_ARG_INFO(arginfo_cli_set_process_title, 0)
+ ZEND_ARG_INFO(0, title)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_cli_get_process_title, 0)
+ZEND_END_ARG_INFO()
+
+PHP_FUNCTION(cli_set_process_title);
+PHP_FUNCTION(cli_get_process_title);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
index 1d2ceff69..a2b85d47b 100644
--- a/sapi/cli/php_cli_server.c
+++ b/sapi/cli/php_cli_server.c
@@ -103,6 +103,8 @@
#include "php_http_parser.h"
#include "php_cli_server.h"
+#include "php_cli_process_title.h"
+
#define OUTPUT_NOT_CHECKED -1
#define OUTPUT_IS_TTY 1
#define OUTPUT_NOT_TTY 0
@@ -429,6 +431,12 @@ zend_module_entry cli_server_module_entry = {
};
/* }}} */
+const zend_function_entry server_additional_functions[] = {
+ PHP_FE(cli_set_process_title, arginfo_cli_set_process_title)
+ PHP_FE(cli_get_process_title, arginfo_cli_get_process_title)
+ {NULL, NULL, NULL}
+};
+
static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */
{
if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) {
diff --git a/sapi/cli/php_cli_server.h b/sapi/cli/php_cli_server.h
index ed716f99f..9a29626c7 100644
--- a/sapi/cli/php_cli_server.h
+++ b/sapi/cli/php_cli_server.h
@@ -23,6 +23,7 @@
#include "SAPI.h"
+extern const zend_function_entry server_additional_functions[];
extern sapi_module_struct cli_server_sapi_module;
extern int do_cli_server(int argc, char **argv TSRMLS_DC);
diff --git a/sapi/cli/ps_title.c b/sapi/cli/ps_title.c
new file mode 100644
index 000000000..a2e47f031
--- /dev/null
+++ b/sapi/cli/ps_title.c
@@ -0,0 +1,426 @@
+/*
+ * PostgreSQL is released under the PostgreSQL License, a liberal Open Source
+ * license, similar to the BSD or MIT licenses.
+ * PostgreSQL Database Management System (formerly known as Postgres, then as
+ * Postgres95)
+ *
+ * Portions Copyright (c) 1996-2013, The PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1994, The Regents of the University of California
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without a written
+ * agreement is hereby granted, provided that the above copyright notice
+ * and this paragraph and the following two paragraphs appear in all copies.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+ * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+ * EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
+ * "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * The following code is adopted from the PostgreSQL's ps_status(.h/.c).
+ */
+
+#include "ps_title.h"
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#include <windows.h>
+#include <process.h>
+#else
+#include "php_config.h"
+extern char** environ;
+#endif
+
+#ifdef HAVE_SYS_PSTAT_H
+#include <sys/pstat.h> /* for HP-UX */
+#endif
+#ifdef HAVE_PS_STRINGS
+#include <machine/vmparam.h> /* for old BSD */
+#include <sys/exec.h>
+#endif
+#if defined(DARWIN)
+#include <crt_externs.h>
+#endif
+
+/*
+ * Ways of updating ps display:
+ *
+ * PS_USE_SETPROCTITLE
+ * use the function setproctitle(const char *, ...)
+ * (newer BSD systems)
+ * PS_USE_PSTAT
+ * use the pstat(PSTAT_SETCMD, )
+ * (HPUX)
+ * PS_USE_PS_STRINGS
+ * assign PS_STRINGS->ps_argvstr = "string"
+ * (some BSD systems)
+ * PS_USE_CHANGE_ARGV
+ * assign argv[0] = "string"
+ * (some other BSD systems)
+ * PS_USE_CLOBBER_ARGV
+ * write over the argv and environment area
+ * (Linux and most SysV-like systems)
+ * PS_USE_WIN32
+ * push the string out as the name of a Windows event
+ * PS_USE_NONE
+ * don't update ps display
+ * (This is the default, as it is safest.)
+ */
+#if defined(HAVE_SETPROCTITLE)
+#define PS_USE_SETPROCTITLE
+#elif defined(HAVE_SYS_PSTAT_H) && defined(PSTAT_SETCMD)
+#define PS_USE_PSTAT
+#elif defined(HAVE_PS_STRINGS)
+#define PS_USE_PS_STRINGS
+#elif defined(BSD) && !defined(DARWIN)
+#define PS_USE_CHANGE_ARGV
+#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__osf__) || defined(DARWIN)
+#define PS_USE_CLOBBER_ARGV
+#elif defined(PHP_WIN32)
+#define PS_USE_WIN32
+#else
+#define PS_USE_NONE
+#endif
+
+/* Different systems want the buffer padded differently */
+#if defined(_AIX) || defined(__linux__) || defined(DARWIN)
+#define PS_PADDING '\0'
+#else
+#define PS_PADDING ' '
+#endif
+
+#ifdef PS_USE_WIN32
+static char windows_error_details[64];
+static char ps_buffer[MAX_PATH];
+static const size_t ps_buffer_size = MAX_PATH;
+#elif defined(PS_USE_CLOBBER_ARGV)
+static char *ps_buffer; /* will point to argv area */
+static size_t ps_buffer_size; /* space determined at run time */
+#else
+#define PS_BUFFER_SIZE 256
+static char ps_buffer[PS_BUFFER_SIZE];
+static const size_t ps_buffer_size = PS_BUFFER_SIZE;
+#endif
+
+static size_t ps_buffer_cur_len; /* actual string length in ps_buffer */
+
+/* save the original argv[] location here */
+static int save_argc;
+static char** save_argv;
+
+
+/*
+ * Call this method early, before any code has used the original argv passed in
+ * from main().
+ * If needed, this code will make deep copies of argv and environ and return
+ * these to the caller for further use. The original argv is then 'clobbered'
+ * to store the process title.
+ */
+char** save_ps_args(int argc, char** argv)
+{
+ save_argc = argc;
+ save_argv = argv;
+
+#if defined(PS_USE_CLOBBER_ARGV)
+ /*
+ * If we're going to overwrite the argv area, count the available space.
+ * Also move the environment to make additional room.
+ */
+ {
+ char* end_of_area = NULL;
+ int non_contiguous_area = 0;
+ char** new_environ;
+ int i;
+
+ /*
+ * check for contiguous argv strings
+ */
+ for (i = 0; (non_contiguous_area == 0) && (i < argc); i++)
+ {
+ if (i != 0 && end_of_area + 1 != argv[i])
+ non_contiguous_area = 1;
+ end_of_area = argv[i] + strlen(argv[i]);
+ }
+
+ /*
+ * check for contiguous environ strings following argv
+ */
+ for (i = 0; (non_contiguous_area == 0) && (environ[i] != NULL); i++)
+ {
+ if (end_of_area + 1 != environ[i])
+ non_contiguous_area = 1;
+ end_of_area = environ[i] + strlen(environ[i]);
+ }
+
+ if (non_contiguous_area != 0)
+ goto clobber_error;
+
+ ps_buffer = argv[0];
+ ps_buffer_size = end_of_area - argv[0];
+
+ /*
+ * move the environment out of the way
+ */
+ new_environ = (char **) malloc((i + 1) * sizeof(char *));
+ if (!new_environ)
+ goto clobber_error;
+ for (i = 0; environ[i] != NULL; i++)
+ {
+ new_environ[i] = strdup(environ[i]);
+ if (!new_environ[i])
+ goto clobber_error;
+ }
+ new_environ[i] = NULL;
+ environ = new_environ;
+
+ }
+#endif /* PS_USE_CLOBBER_ARGV */
+
+#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
+ /*
+ * If we're going to change the original argv[] then make a copy for
+ * argument parsing purposes.
+ *
+ * (NB: do NOT think to remove the copying of argv[]!
+ * On some platforms, getopt() keeps pointers into the argv array, and
+ * will get horribly confused when it is re-called to analyze a subprocess'
+ * argument string if the argv storage has been clobbered meanwhile.
+ * Other platforms have other dependencies on argv[].)
+ */
+ {
+ char** new_argv;
+ int i;
+
+ new_argv = (char **) malloc((argc + 1) * sizeof(char *));
+ if (!new_argv)
+ goto clobber_error;
+ for (i = 0; i < argc; i++)
+ {
+ new_argv[i] = strdup(argv[i]);
+ if (!new_argv[i])
+ goto clobber_error;
+ }
+ new_argv[argc] = NULL;
+
+#if defined(DARWIN)
+ /*
+ * Darwin (and perhaps other NeXT-derived platforms?) has a static
+ * copy of the argv pointer, which we may fix like so:
+ */
+ *_NSGetArgv() = new_argv;
+#endif
+
+ argv = new_argv;
+
+ }
+#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
+
+#if defined(PS_USE_CLOBBER_ARGV)
+ {
+ /* make extra argv slots point at end_of_area (a NUL) */
+ int i;
+ for (i = 1; i < save_argc; i++)
+ save_argv[i] = ps_buffer + ps_buffer_size;
+ }
+#endif /* PS_USE_CLOBBER_ARGV */
+
+#ifdef PS_USE_CHANGE_ARGV
+ save_argv[0] = ps_buffer; /* ps_buffer here is a static const array of size PS_BUFFER_SIZE */
+ save_argv[1] = NULL;
+#endif /* PS_USE_CHANGE_ARGV */
+
+ return argv;
+
+#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
+clobber_error:
+ /* probably can't happen?!
+ * if we ever get here, argv still points to originally passed
+ * in argument
+ */
+ save_argv = NULL;
+ save_argc = 0;
+ ps_buffer = NULL;
+ ps_buffer_size = 0;
+ return argv;
+#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
+}
+
+/*
+ * Returns PS_TITLE_SUCCESS if the OS supports this functionality
+ * and the init function was called.
+ * Otherwise returns NOT_AVAILABLE or NOT_INITIALIZED
+ */
+int is_ps_title_available()
+{
+#ifdef PS_USE_NONE
+ return PS_TITLE_NOT_AVAILABLE; /* disabled functionality */
+#endif
+
+ if (!save_argv)
+ return PS_TITLE_NOT_INITIALIZED;
+
+#ifdef PS_USE_CLOBBER_ARGV
+ if (!ps_buffer)
+ return PS_TITLE_BUFFER_NOT_AVAILABLE;
+#endif /* PS_USE_CLOBBER_ARGV */
+
+ return PS_TITLE_SUCCESS;
+}
+
+/*
+ * Convert error codes into error strings
+ */
+const char* ps_title_errno(int rc)
+{
+ switch(rc)
+ {
+ case PS_TITLE_SUCCESS:
+ return "Success";
+
+ case PS_TITLE_NOT_AVAILABLE:
+ return "Not available on this OS";
+
+ case PS_TITLE_NOT_INITIALIZED:
+ return "Not initialized correctly";
+
+ case PS_TITLE_BUFFER_NOT_AVAILABLE:
+ return "Buffer not contiguous";
+
+#ifdef PS_USE_WIN32
+ case PS_TITLE_WINDOWS_ERROR:
+ sprintf(windows_error_details, "Windows error code: %d", GetLastError());
+ return windows_error_details;
+#endif
+ }
+
+ return "Unknown error code";
+}
+
+/*
+ * Set a new process title.
+ * Returns the appropriate error code if if there's an error
+ * (like the functionality is compile time disabled, or the
+ * save_ps_args() was not called.
+ * Else returns 0 on success.
+ */
+int set_ps_title(const char* title)
+{
+ int rc = is_ps_title_available();
+ if (rc != PS_TITLE_SUCCESS)
+ return rc;
+
+ strncpy(ps_buffer, title, ps_buffer_size);
+ ps_buffer[ps_buffer_size - 1] = '\0';
+ ps_buffer_cur_len = strlen(ps_buffer);
+
+#ifdef PS_USE_SETPROCTITLE
+ setproctitle("%s", ps_buffer);
+#endif
+
+#ifdef PS_USE_PSTAT
+ {
+ union pstun pst;
+
+ pst.pst_command = ps_buffer;
+ pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0);
+ }
+#endif /* PS_USE_PSTAT */
+
+#ifdef PS_USE_PS_STRINGS
+ PS_STRINGS->ps_nargvstr = 1;
+ PS_STRINGS->ps_argvstr = ps_buffer;
+#endif /* PS_USE_PS_STRINGS */
+
+#ifdef PS_USE_CLOBBER_ARGV
+ /* pad unused memory */
+ if (ps_buffer_cur_len < ps_buffer_size)
+ {
+ memset(ps_buffer + ps_buffer_cur_len, PS_PADDING,
+ ps_buffer_size - ps_buffer_cur_len);
+ }
+#endif /* PS_USE_CLOBBER_ARGV */
+
+#ifdef PS_USE_WIN32
+ {
+ if (!SetConsoleTitle(ps_buffer))
+ return PS_TITLE_WINDOWS_ERROR;
+ }
+#endif /* PS_USE_WIN32 */
+
+ return PS_TITLE_SUCCESS;
+}
+
+/*
+ * Returns the current ps_buffer value into string. On some platforms
+ * the string will not be null-terminated, so return the effective
+ * length into *displen.
+ * The return code indicates the error.
+ */
+int get_ps_title(int *displen, const char** string)
+{
+ int rc = is_ps_title_available();
+ if (rc != PS_TITLE_SUCCESS)
+ return rc;
+
+#ifdef PS_USE_WIN32
+ if (!(ps_buffer_cur_len = GetConsoleTitle(ps_buffer, ps_buffer_size)))
+ return PS_TITLE_WINDOWS_ERROR;
+#endif
+ *displen = (int)ps_buffer_cur_len;
+ *string = ps_buffer;
+ return PS_TITLE_SUCCESS;
+}
+
+/*
+ * Clean up the allocated argv and environ if applicable. Only call
+ * this right before exiting.
+ * This isn't needed per-se because the OS will clean-up anyway, but
+ * having and calling this will ensure Valgrind doesn't output 'false
+ * positives'.
+ */
+void cleanup_ps_args(char **argv)
+{
+#ifndef PS_USE_NONE
+ if (save_argv)
+ {
+ save_argv = NULL;
+ save_argc = 0;
+
+#ifdef PS_USE_CLOBBER_ARGV
+ {
+ int i;
+ for (i = 0; environ[i] != NULL; i++)
+ free(environ[i]);
+ free(environ);
+ }
+#endif /* PS_USE_CLOBBER_ARGV */
+
+#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
+ {
+ int i;
+ for (i=0; argv[i] != NULL; i++)
+ free(argv[i]);
+ free(argv);
+ }
+#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
+ }
+#endif /* PS_USE_NONE */
+
+ return;
+}
diff --git a/sapi/cli/ps_title.h b/sapi/cli/ps_title.h
new file mode 100644
index 000000000..5623653e4
--- /dev/null
+++ b/sapi/cli/ps_title.h
@@ -0,0 +1,42 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 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: |
+ | http://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: Keyur Govande <kgovande@gmail.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PS_TITLE_HEADER
+#define PS_TITLE_HEADER
+
+#define PS_TITLE_SUCCESS 0
+#define PS_TITLE_NOT_AVAILABLE 1
+#define PS_TITLE_NOT_INITIALIZED 2
+#define PS_TITLE_BUFFER_NOT_AVAILABLE 3
+#define PS_TITLE_WINDOWS_ERROR 4
+
+extern char** save_ps_args(int argc, char** argv);
+
+extern int set_ps_title(const char* new_str);
+
+extern int get_ps_title(int* displen, const char** string);
+
+extern const char* ps_title_errno(int rc);
+
+extern int is_ps_title_available();
+
+extern void cleanup_ps_args(char **argv);
+
+#endif // PS_TITLE_HEADER
diff --git a/sapi/cli/tests/cli_process_title_unix.phpt b/sapi/cli/tests/cli_process_title_unix.phpt
new file mode 100644
index 000000000..c2632704c
--- /dev/null
+++ b/sapi/cli/tests/cli_process_title_unix.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Check cli_process_title support on Unix
+--SKIPIF--
+<?php
+if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
+ die("skip");
+?>
+--FILE--
+<?php
+echo "*** Testing setting the process title ***\n";
+
+$set_title = $original_title = uniqid("title", true);
+$pid = getmypid();
+
+if (cli_set_process_title($original_title) === true)
+ echo "Successfully set title\n";
+
+$ps_output = shell_exec("ps -p $pid -o command | tail -n 1");
+
+if ($ps_output === null)
+{
+ echo "ps failed\n";
+ die();
+}
+
+$loaded_title = trim($ps_output);
+if (strpos(strtoupper(substr(PHP_OS, 0, 13)), "BSD") !== false)
+{
+ // Fix up title for BSD
+ $set_title = "php: $original_title (php)";
+}
+
+if ($loaded_title == $set_title)
+ echo "Successfully verified title using ps\n";
+else
+ echo "Actually loaded from ps: $loaded_title\n";
+
+$read_title = cli_get_process_title();
+if ($read_title == $original_title)
+ echo "Successfully verified title using get\n";
+else
+ echo "Actually loaded from get: $read_title\n";
+
+?>
+--EXPECTF--
+*** Testing setting the process title ***
+Successfully set title
+Successfully verified title using ps
+Successfully verified title using get
diff --git a/sapi/cli/tests/cli_process_title_windows.phpt b/sapi/cli/tests/cli_process_title_windows.phpt
new file mode 100644
index 000000000..309c09c0e
--- /dev/null
+++ b/sapi/cli/tests/cli_process_title_windows.phpt
@@ -0,0 +1,82 @@
+--TEST--
+Check cli_process_title support in Windows
+--SKIPIF--
+<?php
+if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
+ die("skip");
+?>
+--FILE--
+<?php
+
+// On Windows 8 and Server 2012, this test does not work the same way. When the PowerShell
+// command "get-process" is executed using shell_exec, it overwrites the ConsoleTitle with
+// "Windows PowerShell" and this title ONLY clears away when the php.exe process exits
+// i.e. the test finishes.
+// On older versions like Windows 7 though, running the command appends
+// "Windows PowerShell" to the ConsoleTitle temporarily and the title reverts
+// back to the original once shell_exec is done.
+// Hence on Windows 8, we don't verify that the title is actually set by
+// cli_set_process_title(). We're only making the API calls to ensure there are
+// no warnings/errors.
+
+$is_windows8 = false;
+$ps_output = shell_exec("PowerShell \"(Get-Host).UI.RawUI.WindowTitle\"");
+if ($ps_output === null)
+{
+ echo "Get-Host failed\n";
+ die();
+}
+
+$ps_output = trim($ps_output);
+if (($ps_output == "Windows PowerShell") || ($ps_output == "Administrator: Windows PowerShell"))
+ $is_windows8 = true;
+
+echo "*** Testing setting the process title ***\n";
+
+$original_title = uniqid("title", true);
+$pid = getmypid();
+
+if (cli_set_process_title($original_title) === true)
+ echo "Successfully set title\n";
+
+if ($is_windows8)
+{
+ $loaded_title = $original_title;
+}
+else
+{
+ $loaded_title = shell_exec("PowerShell \"get-process cmd*,powershell* | Select-Object mainWindowTitle | ft -hide\"");
+
+ if ($loaded_title === null)
+ {
+ echo "Reading title using get-process failed\n";
+ die();
+ }
+
+ // Kind of convoluted. So when the test is run on Windows 7 or older, the console where
+ // the run-tests.php is executed forks a php.exe, which forks a cmd.exe, which then forks
+ // a final php.exe to run the actual test. But the console title is set for the original console.
+ // I couldn't figure out a good way to navigate this, so we're "grep'ing" all possible
+ // console windows for our very unique title. It should occur exactly once in the grep
+ // output.
+ if (substr_count($loaded_title, $original_title, 0) == 1)
+ $loaded_title = $original_title;
+}
+
+if ($loaded_title == $original_title)
+ echo "Successfully verified title using get-process\n";
+else
+ echo "Actually loaded from get-process: $loaded_title\n";
+
+$read_title = cli_get_process_title();
+if (substr_count($read_title, $original_title, 0) == 1)
+ echo "Successfully verified title using get\n";
+else
+ echo "Actually loaded from get: $read_title\n";
+
+?>
+--EXPECTF--
+*** Testing setting the process title ***
+Successfully set title
+Successfully verified title using get-process
+Successfully verified title using get \ No newline at end of file
diff --git a/tests/output/ob_017.phpt b/tests/output/ob_017.phpt
index 517fafe99..1dc5fc59b 100644
--- a/tests/output/ob_017.phpt
+++ b/tests/output/ob_017.phpt
@@ -1,5 +1,7 @@
--TEST--
output buffering - stati
+--INI--
+opcache.optimization_level=0
--FILE--
<?php
$stati = array();
diff --git a/tests/output/ob_start_basic_004.phpt b/tests/output/ob_start_basic_004.phpt
index 16f09e8a9..710df7a8a 100644
--- a/tests/output/ob_start_basic_004.phpt
+++ b/tests/output/ob_start_basic_004.phpt
@@ -1,5 +1,7 @@
--TEST--
ob_start() chunk_size: confirm buffer is flushed after any output call that causes its length to equal or exceed chunk_size.
+--INI--
+opcache.optimization_level=0
--FILE--
<?php
/*
diff --git a/win32/build/mkdist.php b/win32/build/mkdist.php
index 5ed9bdc81..947af9fbe 100644
--- a/win32/build/mkdist.php
+++ b/win32/build/mkdist.php
@@ -443,7 +443,7 @@ function make_phar_dot_phar($dist_dir)
$phar->setStub(implode('', $stub));
echo "Creating phar.phar.bat\n";
- file_put_contents($dist_dir . '/phar.phar.bat', "%~dp0php.exe %~dp0pharcommand.phar %*\r\n");
+ file_put_contents($dist_dir . '/phar.phar.bat', "\"%~dp0php.exe\" \"%~dp0pharcommand.phar\" %*\r\n");
}
if (!is_dir($test_dir)) {
diff --git a/win32/globals.c b/win32/globals.c
index 1bbb3b448..b381cc123 100644
--- a/win32/globals.c
+++ b/win32/globals.c
@@ -65,8 +65,6 @@ PHP_RSHUTDOWN_FUNCTION(win32_core_globals)
;
closelog();
- wg->starttime.tv_sec = 0;
- wg->lasttime = 0;
return SUCCESS;
}
diff --git a/win32/php_win32_globals.h b/win32/php_win32_globals.h
index 1686e5df6..b2b07f68e 100644
--- a/win32/php_win32_globals.h
+++ b/win32/php_win32_globals.h
@@ -38,10 +38,6 @@ struct _php_win32_core_globals {
char *log_header;
HANDLE log_source;
- /* time */
- struct timeval starttime;
- __int64 lasttime, freq;
-
HKEY registry_key;
HANDLE registry_event;
HashTable *registry_directories;
diff --git a/win32/time.c b/win32/time.c
index 391a8a81e..77e4504cd 100644
--- a/win32/time.c
+++ b/win32/time.c
@@ -12,13 +12,6 @@
/* $Id$ */
- /**
- *
- * 04-Feb-2001
- * - Added patch by "Vanhanen, Reijo" <Reijo.Vanhanen@helsoft.fi>
- * Improves accuracy of msec
- */
-
/* Include stuff ************************************************************ */
#include <config.w32.h>
@@ -32,98 +25,56 @@
#include <errno.h>
#include "php_win32_globals.h"
-int getfilesystemtime(struct timeval *time_Info)
+typedef VOID (WINAPI *MyGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime);
+
+static MyGetSystemTimeAsFileTime get_time_func(void)
{
- FILETIME ft;
- __int64 ff;
- ULARGE_INTEGER convFromft;
-
- GetSystemTimeAsFileTime(&ft); /* 100 ns blocks since 01-Jan-1641 */
- /* resolution seems to be 0.01 sec */
- /*
- * Do not cast a pointer to a FILETIME structure to either a
- * ULARGE_INTEGER* or __int64* value because it can cause alignment faults on 64-bit Windows.
- * via http://technet.microsoft.com/en-us/library/ms724284(v=vs.85).aspx
- */
- convFromft.HighPart = ft.dwHighDateTime;
- convFromft.LowPart = ft.dwLowDateTime;
- ff = convFromft.QuadPart;
-
- time_Info->tv_sec = (int)(ff/(__int64)10000000-(__int64)11644473600);
- time_Info->tv_usec = (int)(ff % 10000000)/10;
- return 0;
+ MyGetSystemTimeAsFileTime timefunc = NULL;
+ HMODULE hMod = LoadLibrary("kernel32.dll");
+
+ if (hMod) {
+ /* Max possible resolution <1us, win8/server2012 */
+ timefunc = (MyGetSystemTimeAsFileTime)GetProcAddress(hMod, "GetSystemTimePreciseAsFileTime");
+
+ if(!timefunc) {
+ /* 100ns blocks since 01-Jan-1641 */
+ timefunc = (MyGetSystemTimeAsFileTime)GetProcAddress(hMod, "GetSystemTimeAsFileTime");
+ }
+ }
+
+ return timefunc;
}
-
+int getfilesystemtime(struct timeval *tv)
+{
+ FILETIME ft;
+ unsigned __int64 ff = 0;
+ MyGetSystemTimeAsFileTime timefunc;
+
+ timefunc = get_time_func();
+ if (timefunc) {
+ timefunc(&ft);
+ } else {
+ GetSystemTimeAsFileTime(&ft);
+ }
+
+ ff |= ft.dwHighDateTime;
+ ff <<= 32;
+ ff |= ft.dwLowDateTime;
+ ff /= 10; /* convert to microseconds */
+ ff -= 11644473600000000Ui64; /* convert to unix epoch */
+
+ tv->tv_sec = (long)(ff / 1000000UL);
+ tv->tv_usec = (long)(ff % 1000000UL);
+
+ return 0;
+}
PHPAPI int gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info)
{
- __int64 timer;
- LARGE_INTEGER li;
- BOOL b;
- double dt;
- TSRMLS_FETCH();
-
/* Get the time, if they want it */
if (time_Info != NULL) {
- if (PW32G(starttime).tv_sec == 0) {
- b = QueryPerformanceFrequency(&li);
- if (!b) {
- PW32G(starttime).tv_sec = -1;
- }
- else {
- PW32G(freq) = li.QuadPart;
- b = QueryPerformanceCounter(&li);
- if (!b) {
- PW32G(starttime).tv_sec = -1;
- }
- else {
- getfilesystemtime(&PW32G(starttime));
- timer = li.QuadPart;
- dt = (double)timer/PW32G(freq);
- PW32G(starttime).tv_usec -= (int)((dt-(int)dt)*1000000);
- if (PW32G(starttime).tv_usec < 0) {
- PW32G(starttime).tv_usec += 1000000;
- --PW32G(starttime).tv_sec;
- }
- PW32G(starttime).tv_sec -= (int)dt;
- }
- }
- }
- if (PW32G(starttime).tv_sec > 0) {
- b = QueryPerformanceCounter(&li);
- if (!b) {
- PW32G(starttime).tv_sec = -1;
- }
- else {
- timer = li.QuadPart;
- if (timer < PW32G(lasttime)) {
- getfilesystemtime(time_Info);
- dt = (double)timer/PW32G(freq);
- PW32G(starttime) = *time_Info;
- PW32G(starttime).tv_usec -= (int)((dt-(int)dt)*1000000);
- if (PW32G(starttime).tv_usec < 0) {
- PW32G(starttime).tv_usec += 1000000;
- --PW32G(starttime).tv_sec;
- }
- PW32G(starttime).tv_sec -= (int)dt;
- }
- else {
- PW32G(lasttime) = timer;
- dt = (double)timer/PW32G(freq);
- time_Info->tv_sec = PW32G(starttime).tv_sec + (int)dt;
- time_Info->tv_usec = PW32G(starttime).tv_usec + (int)((dt-(int)dt)*1000000);
- if (time_Info->tv_usec >= 1000000) {
- time_Info->tv_usec -= 1000000;
- ++time_Info->tv_sec;
- }
- }
- }
- }
- if (PW32G(starttime).tv_sec < 0) {
- getfilesystemtime(time_Info);
- }
-
+ getfilesystemtime(time_Info);
}
/* Get the timezone, if they want it */
if (timezone_Info != NULL) {