`tmp` can only ever be non-undef if there's a hooked object property, which is
already an `UNEXPECTED()` case. Keep track of whether this case is hit or not
to avoid needlessly calling `zval_ptr_dtor()`.
For:
<?php
$len = 0;
for ($i = 0; $i < 3_000_000; $i++) {
$len += strlen(json_encode(array_fill(0, 20, [])));
}
var_dump($len);
This is ~1.02 faster for a gcc 13.3 release build on a Intel(R) Core(TM)
i7-1365U.
Benchmark 1: /tmp/bench/before /tmp/bench/test6.php
Time (mean ± σ): 762.7 ms ± 3.2 ms [User: 758.5 ms, System: 2.8 ms]
Range (min … max): 759.2 ms … 769.3 ms 10 runs
Benchmark 2: /tmp/bench/after /tmp/bench/test6.php
Time (mean ± σ): 748.3 ms ± 9.0 ms [User: 744.3 ms, System: 3.1 ms]
Range (min … max): 740.8 ms … 766.2 ms 10 runs
Summary
/tmp/bench/after /tmp/bench/test6.php ran
1.02 ± 0.01 times faster than /tmp/bench/before /tmp/bench/test6.php
Instead of using a boolean flag to check for each element whether or not it is
the first, we just unconditionally append a comma after each element and then
remove the last comma at the end.
For:
<?php
$len = 0;
for ($i = 0; $i < 3_000_000; $i++) {
$len += strlen(json_encode(array_fill(0, 20, [])));
}
var_dump($len);
This is ~1.06 faster for a gcc 13.3 release build on a Intel(R) Core(TM)
i7-1365U.
Benchmark 1: /tmp/bench/before /tmp/bench/test6.php
Time (mean ± σ): 819.6 ms ± 2.8 ms [User: 816.4 ms, System: 2.4 ms]
Range (min … max): 816.9 ms … 825.0 ms 10 runs
Benchmark 2: /tmp/bench/after /tmp/bench/test6.php
Time (mean ± σ): 770.8 ms ± 5.8 ms [User: 766.6 ms, System: 2.9 ms]
Range (min … max): 765.3 ms … 785.8 ms 10 runs
Summary
/tmp/bench/after /tmp/bench/test6.php ran
1.06 ± 0.01 times faster than /tmp/bench/before /tmp/bench/test6.php
On s390x the stack is smaller and/or the object dtor code uses more stack,
which causes the destruction of deeply nested objects to crash in these
tests. Here I ensure that objects are released one by one at the end of the
tests to avoid recursive dtor.
Closes GH-16561
Fixes GH-16528
The JSON encoder is recursive, and it's far from easy to make it
iterative. Add a cheap stack limit check to prevent a segfault.
This uses the PHP_JSON_ERROR_DEPTH error code that already talks about
the stack depth. Previously this was only used for the $depth argument.
Closes GH-16059.
When a class (or enum) has no methods, rather than using an array that only
contains `ZEND_FE_END`, use `NULL` for the functions. The implementation of
class registration for internal classes, `do_register_internal_class()` in
zend_API.c, already skips classes where the functions are `NULL`. By removing
these unneeded arrays, we can reduce the size of the header files, while also
removing an unneeded call to zend_register_functions() for each internal class
with no extra methods.
Currently, internal classes are registered with the following code:
INIT_CLASS_ENTRY(ce, "InternalClass", class_InternalClass_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ...;
This has worked well so far, except if InternalClass is readonly. It is because some inheritance checks are run by zend_register_internal_class_ex before ZEND_ACC_READONLY_CLASS is added to ce_flags.
The issue is fixed by adding a zend_register_internal_class_with_flags() zend API function that stubs can use from now on. This function makes sure to add the flags before running any checks. Since the new API is not available in lower PHP versions, gen_stub.php has to keep support for the existing API for PHP 8.3 and below.
* Include from build dir first
This fixes out of tree builds by ensuring that configure artifacts are included
from the build dir.
Before, out of tree builds would preferably include files from the src dir, as
the include path was defined as follows (ignoring includes from ext/ and sapi/) :
-I$(top_builddir)/main
-I$(top_srcdir)
-I$(top_builddir)/TSRM
-I$(top_builddir)/Zend
-I$(top_srcdir)/main
-I$(top_srcdir)/Zend
-I$(top_srcdir)/TSRM
-I$(top_builddir)/
As a result, an out of tree build would include configure artifacts such as
`main/php_config.h` from the src dir.
After this change, the include path is defined as follows:
-I$(top_builddir)/main
-I$(top_builddir)
-I$(top_srcdir)/main
-I$(top_srcdir)
-I$(top_builddir)/TSRM
-I$(top_builddir)/Zend
-I$(top_srcdir)/Zend
-I$(top_srcdir)/TSRM
* Fix extension include path for out of tree builds
* Include config.h with the brackets form
`#include "config.h"` searches in the directory containing the including-file
before any other include path. This can include the wrong config.h when building
out of tree and a config.h exists in the source tree.
Using `#include <config.h>` uses exclusively the include path, and gives
priority to the build dir.
The --no-generation-date flag is a common re2c flag used in all re2c
invocations. This adds the 2nd optional argument to PHP_PROG_RE2C M4
macro in BC manner to set the default re2c command-line options and sets
the default RE2C_FLAGS similarly on Windows.
This syncs the installed sapi and extension headers on *nix and Windows
systems by installing only what is intended outside of php-src.
- ext/gd: without gd_arginfo.h and gd_compat.h
- ext/hash: php_hash_joaat.h and php_hash_fnv.h added also on Windows
installation; xxhash/xxhash.h added on both installations as it is
included in php_hash_xxhash.h; Include path for xxhash.h changed to
relative so the php_hash_xxhash.h can be included outside of php-src;
Redundant include flags removed
- ext/iconv: without iconv_arginfo.h
- ext/mysqli: mysqli_mysqlnd.h was missing on Windows
- ext/phar: php_phar.h was missing on Windows
- ext/sodium: php_libsodium.h was missing on *nix
- ext/xml: without xml_arginfo.h
- sapi/cli: cli.h was missing on Windows
Closes GH-13210
Closes GH-13213
This PR introduces a new way of recursion protection in JSON, var_dump
and friends. It fixes issue in master for __debugInfo and also improves
perf for jsonSerializable in some cases. More info can be found in
GH-10020.
Closes GH-11812
To prevent build failures like:
make: *** No rule to make target '/code/master/ext/json/php_json_scanner_defs.h', needed by 'ext/json/json_scanner.lo'. Stop.
* Add `json_validate(string $json, int $depth = 512, int $flags = 0): bool` from https://wiki.php.net/rfc/json_validate
* In json_validate, use a different set of C no-op functions for creating/updating
arrays/objects when validating while reusing the unmodified parser/scanner code
* Forbid unsupported flags in json_validate()
* Remove test of passing NULL as parameter (normal behavior of https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg for internal functions)
Co-authored-by: jcm <juan.carlos.morales@tradebyte.com>