Skip to content

Commit 90f8635

Browse files
authored
Merge branch 'master' into master
2 parents 474b13f + 1cff181 commit 90f8635

File tree

100 files changed

+1389
-332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1389
-332
lines changed

.github/workflows/real-time-benchmark.yml

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ on:
4242
- "0"
4343
- "1"
4444
- "2"
45+
run_micro_bench:
46+
description: 'Whether to run the micro_bench.php test'
47+
required: true
48+
default: "0"
49+
type: choice
50+
options:
51+
- "0"
52+
- "1"
4553
permissions:
4654
contents: read
4755
pull-requests: write
@@ -59,10 +67,11 @@ jobs:
5967
COMMIT: ${{ github.sha }}
6068
BASELINE_COMMIT: "d5f6e56610c729710073350af318c4ea1b292cfe"
6169
ID: "master"
62-
OPCACHE: ${{ inputs.opcache || '1' }}
63-
BASELINE_OPCACHE: ${{ inputs.baseline_opcache || '2' }}
64-
JIT: ${{ inputs.jit || '1' }}
65-
INSTRUCTION_COUNT: ${{ inputs.instruction_count || '0' }}
70+
OPCACHE: "1"
71+
BASELINE_OPCACHE: "2"
72+
JIT: "1"
73+
INSTRUCTION_COUNT: "1"
74+
RUN_MICRO_BENCH: "0"
6675
YEAR: ""
6776
steps:
6877
- name: Setup benchmark environment
@@ -88,6 +97,12 @@ jobs:
8897
echo "BASELINE_COMMIT=$BASELINE_COMMIT" >> $GITHUB_ENV
8998
9099
echo "ID=benchmarked" >> $GITHUB_ENV
100+
101+
echo "OPCACHE=${{ inputs.opcache }}" >> $GITHUB_ENV
102+
echo "BASELINE_OPCACHE=${{ inputs.baseline_opcache }}" >> $GITHUB_ENV
103+
echo "JIT=${{ inputs.jit }}" >> $GITHUB_ENV
104+
echo "INSTRUCTION_COUNT=${{ inputs.instruction_count }}" >> $GITHUB_ENV
105+
echo "RUN_MICRO_BENCH=${{ inputs.run_micro_bench }}" >> $GITHUB_ENV
91106
fi
92107
93108
- name: Install dependencies
@@ -250,7 +265,10 @@ jobs:
250265
cp ./php-version-benchmarks/config/test/2_symfony_main.ini.dist ./php-version-benchmarks/config/test/2_symfony_main.ini
251266
cp ./php-version-benchmarks/config/test/4_wordpress.ini.dist ./php-version-benchmarks/config/test/4_wordpress.ini
252267
cp ./php-version-benchmarks/config/test/5_bench.php.ini.dist ./php-version-benchmarks/config/test/5_bench.php.ini
253-
cp ./php-version-benchmarks/config/test/6_micro_bench.php.ini.dist ./php-version-benchmarks/config/test/6_micro_bench.php.ini
268+
269+
if [ "${{ env.RUN_MICRO_BENCH }}" -eq "1" ]; then
270+
cp ./php-version-benchmarks/config/test/6_micro_bench.php.ini.dist ./php-version-benchmarks/config/test/6_micro_bench.php.ini
271+
fi
254272
- name: Run benchmark
255273
run: ./php-version-benchmarks/benchmark.sh run aws
256274
- name: Store results

NEWS

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,33 @@ PHP NEWS
1212
error in PHP 9. (alexandre-daubois)
1313
. Fixed OSS-Fuzz #439125710 (Pipe cannot be used in write context).
1414
(nielsdos)
15+
. Added support for configuring the URI parser for the FTP/FTPS as well as
16+
the SSL/TLS stream wrappers as described in
17+
https://wiki.php.net/rfc/url_parsing_api#plugability. (kocsismate)
18+
19+
- Filter:
20+
. Added support for configuring the URI parser for FILTER_VALIDATE_URL
21+
as described in https://wiki.php.net/rfc/url_parsing_api#plugability.
22+
(kocsismate)
1523

1624
- ODBC:
1725
. Remove ODBCVER and assume ODBC 3.5. (Calvin Buckley)
1826

27+
- Opcache:
28+
. Fixed bug GH-19493 (JIT variable not stored before YIELD). (Arnaud)
29+
1930
- OpenSSL:
2031
. Implement #81724 (openssl_cms_encrypt only allows specific ciphers).
2132
(Jakub Zelenka)
2233

2334
- Session:
2435
. Added support for partitioned cookies. (nielsdos)
2536

37+
- SOAP:
38+
. Added support for configuring the URI parser for SoapClient::_doRequest()
39+
as described in https://wiki.php.net/rfc/url_parsing_api#plugability.
40+
(kocsismate)
41+
2642
- SPL:
2743
. Deprecate ArrayObject and ArrayIterator with objects. (Girgias)
2844

UPGRADING.INTERNALS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ PHP 8.5 INTERNALS UPGRADE NOTES
8585
. ext/standard/php_smart_string.h and ext/standard/php_smart_string_public.h
8686
were removed. Use the corresponding headers in Zend/ instead.
8787

88+
- URI
89+
. Internal API for URI handling was added via the php_uri_*() functions.
90+
8891
========================
8992
2. Build system changes
9093
========================

Zend/zend_gc.c

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@
172172
#define GC_IDX2PTR(idx) (GC_G(buf) + (idx))
173173
#define GC_PTR2IDX(ptr) ((ptr) - GC_G(buf))
174174

175+
/* Get the value to be placed in an unused buffer entry with the specified next unused list index */
175176
#define GC_IDX2LIST(idx) ((void*)(uintptr_t)(((idx) * sizeof(void*)) | GC_UNUSED))
177+
/* Get the index of the next item in the unused list from the given root buffer entry. */
176178
#define GC_LIST2IDX(list) (((uint32_t)(uintptr_t)(list)) / sizeof(void*))
177179

178180
/* GC buffers */
@@ -228,10 +230,16 @@
228230
} while (0)
229231

230232
/* unused buffers */
233+
234+
/* Are there any unused root buffer entries? */
231235
#define GC_HAS_UNUSED() \
232236
(GC_G(unused) != GC_INVALID)
237+
238+
/* Get the next unused entry and remove it from the list */
233239
#define GC_FETCH_UNUSED() \
234240
gc_fetch_unused()
241+
242+
/* Add a root buffer entry to the unused list */
235243
#define GC_LINK_UNUSED(root) \
236244
gc_link_unused(root)
237245

@@ -244,12 +252,23 @@
244252

245253
ZEND_API int (*gc_collect_cycles)(void);
246254

255+
/* The type of a root buffer entry.
256+
*
257+
* The lower two bits are used for flags and need to be masked out to
258+
* reconstruct a pointer.
259+
*
260+
* When a node in the root buffer is removed, the non-flag bits of the
261+
* unused entry are used to store the index of the next entry in the unused
262+
* list. */
247263
typedef struct _gc_root_buffer {
248264
zend_refcounted *ref;
249265
} gc_root_buffer;
250266

251267
typedef struct _zend_gc_globals {
252-
gc_root_buffer *buf; /* preallocated arrays of buffers */
268+
/* The root buffer, which stores possible roots of reference cycles. It is
269+
* also used to store garbage to be collected at the end of a run.
270+
* A single array which is reallocated as necessary. */
271+
gc_root_buffer *buf;
253272

254273
bool gc_enabled;
255274
bool gc_active; /* GC currently running, forbid nested GC */
@@ -262,13 +281,13 @@ typedef struct _zend_gc_globals {
262281
uint32_t buf_size; /* size of the GC buffer */
263282
uint32_t num_roots; /* number of roots in GC buffer */
264283

265-
uint32_t gc_runs;
266-
uint32_t collected;
284+
uint32_t gc_runs; /* number of GC runs since reset */
285+
uint32_t collected; /* number of collected nodes since reset */
267286

268-
zend_hrtime_t activated_at;
269-
zend_hrtime_t collector_time;
270-
zend_hrtime_t dtor_time;
271-
zend_hrtime_t free_time;
287+
zend_hrtime_t activated_at; /* the timestamp of the last reset */
288+
zend_hrtime_t collector_time; /* time spent running GC (ns) */
289+
zend_hrtime_t dtor_time; /* time spent calling destructors (ns) */
290+
zend_hrtime_t free_time; /* time spent destroying nodes and freeing memory (ns) */
272291

273292
uint32_t dtor_idx; /* root buffer index */
274293
uint32_t dtor_end;
@@ -313,6 +332,7 @@ static zend_gc_globals gc_globals;
313332

314333
typedef struct _gc_stack gc_stack;
315334

335+
/* The stack used for graph traversal is stored as a linked list of segments */
316336
struct _gc_stack {
317337
gc_stack *prev;
318338
gc_stack *next;
@@ -375,6 +395,11 @@ static void gc_stack_free(gc_stack *stack)
375395
}
376396
}
377397

398+
/* Map a full index to a compressed index.
399+
*
400+
* The root buffer can have up to 2^30 entries, but we only have 20 bits to
401+
* store the index. So we use the 1<<19 bit as a compression flag and use the
402+
* other 19 bits to store the index modulo 2^19. */
378403
static zend_always_inline uint32_t gc_compress(uint32_t idx)
379404
{
380405
if (EXPECTED(idx < GC_MAX_UNCOMPRESSED)) {
@@ -383,6 +408,9 @@ static zend_always_inline uint32_t gc_compress(uint32_t idx)
383408
return (idx % GC_MAX_UNCOMPRESSED) | GC_MAX_UNCOMPRESSED;
384409
}
385410

411+
/* Find the root buffer entry given a pointer and a compressed index.
412+
* Iterate through the root buffer in steps of 2^19 until the pointer
413+
* matches. */
386414
static zend_always_inline gc_root_buffer* gc_decompress(zend_refcounted *ref, uint32_t idx)
387415
{
388416
gc_root_buffer *root = GC_IDX2PTR(idx);
@@ -401,6 +429,8 @@ static zend_always_inline gc_root_buffer* gc_decompress(zend_refcounted *ref, ui
401429
}
402430
}
403431

432+
/* Get the index of the next unused root buffer entry, and remove it from the
433+
* unused list. GC_HAS_UNUSED() must be true before calling this. */
404434
static zend_always_inline uint32_t gc_fetch_unused(void)
405435
{
406436
uint32_t idx;
@@ -414,6 +444,7 @@ static zend_always_inline uint32_t gc_fetch_unused(void)
414444
return idx;
415445
}
416446

447+
/* Add a root buffer entry to the unused list */
417448
static zend_always_inline void gc_link_unused(gc_root_buffer *root)
418449
{
419450
root->ref = GC_IDX2LIST(GC_G(unused));
@@ -463,6 +494,7 @@ static void gc_trace_ref(zend_refcounted *ref) {
463494
}
464495
#endif
465496

497+
/* Mark a root buffer entry unused */
466498
static zend_always_inline void gc_remove_from_roots(gc_root_buffer *root)
467499
{
468500
GC_LINK_UNUSED(root);
@@ -565,6 +597,8 @@ void gc_reset(void)
565597
GC_G(activated_at) = zend_hrtime();
566598
}
567599

600+
/* Enable/disable the garbage collector.
601+
* Initialize globals if necessary. */
568602
ZEND_API bool gc_enable(bool enable)
569603
{
570604
bool old_enabled = GC_G(gc_enabled);
@@ -584,6 +618,7 @@ ZEND_API bool gc_enabled(void)
584618
return GC_G(gc_enabled);
585619
}
586620

621+
/* Protect the GC root buffer (prevent additions) */
587622
ZEND_API bool gc_protect(bool protect)
588623
{
589624
bool old_protected = GC_G(gc_protected);
@@ -621,6 +656,7 @@ static void gc_grow_root_buffer(void)
621656
GC_G(buf_size) = new_size;
622657
}
623658

659+
/* Adjust the GC activation threshold given the number of nodes collected by the last run */
624660
static void gc_adjust_threshold(int count)
625661
{
626662
uint32_t new_threshold;
@@ -651,6 +687,7 @@ static void gc_adjust_threshold(int count)
651687
}
652688
}
653689

690+
/* Perform a GC run and then add a node as a possible root. */
654691
static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refcounted *ref)
655692
{
656693
uint32_t idx;
@@ -695,6 +732,8 @@ static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refc
695732
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
696733
}
697734

735+
/* Add a possible root node to the buffer.
736+
* Maybe perform a GC run. */
698737
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
699738
{
700739
uint32_t idx;
@@ -731,6 +770,7 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
731770
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
732771
}
733772

773+
/* Add an extra root during a GC run */
734774
static void ZEND_FASTCALL gc_extra_root(zend_refcounted *ref)
735775
{
736776
uint32_t idx;
@@ -764,6 +804,7 @@ static void ZEND_FASTCALL gc_extra_root(zend_refcounted *ref)
764804
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
765805
}
766806

807+
/* Remove a node from the root buffer given its compressed index */
767808
static zend_never_inline void ZEND_FASTCALL gc_remove_compressed(zend_refcounted *ref, uint32_t idx)
768809
{
769810
gc_root_buffer *root = gc_decompress(ref, idx);
@@ -793,6 +834,10 @@ ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref)
793834
gc_remove_from_roots(root);
794835
}
795836

837+
/* Mark all nodes reachable from ref as black (live). Restore the reference
838+
* counts decremented by gc_mark_grey(). See ScanBlack() in Bacon & Rajan.
839+
* To implement a depth-first search, discovered nodes are added to a stack
840+
* which is processed iteratively. */
796841
static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
797842
{
798843
HashTable *ht;
@@ -992,6 +1037,8 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
9921037
}
9931038
}
9941039

1040+
/* Traverse the graph of nodes referred to by ref. Decrement the reference
1041+
* counts and mark visited nodes grey. See MarkGray() in Bacon & Rajan. */
9951042
static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
9961043
{
9971044
HashTable *ht;
@@ -1204,6 +1251,9 @@ static void gc_compact(void)
12041251
}
12051252
}
12061253

1254+
/* For all roots marked purple, traverse the graph, decrementing the reference
1255+
* count of their child nodes. Mark visited nodes grey so that they are not
1256+
* visited again. See MarkRoots() in Bacon & Rajan. */
12071257
static void gc_mark_roots(gc_stack *stack)
12081258
{
12091259
gc_root_buffer *current, *last;
@@ -1223,6 +1273,10 @@ static void gc_mark_roots(gc_stack *stack)
12231273
}
12241274
}
12251275

1276+
/* Traverse the reference graph of ref. Evaluate grey nodes and mark them
1277+
* black (to keep) or white (to free). Note that nodes initially marked white
1278+
* may later become black if they are visited from a live node.
1279+
* See Scan() in Bacon & Rajan. */
12261280
static void gc_scan(zend_refcounted *ref, gc_stack *stack)
12271281
{
12281282
HashTable *ht;
@@ -1376,6 +1430,7 @@ static void gc_scan(zend_refcounted *ref, gc_stack *stack)
13761430
}
13771431
}
13781432

1433+
/* Scan all roots, coloring grey nodes black or white */
13791434
static void gc_scan_roots(gc_stack *stack)
13801435
{
13811436
uint32_t idx, end;
@@ -1409,6 +1464,8 @@ static void gc_scan_roots(gc_stack *stack)
14091464
}
14101465
}
14111466

1467+
/* Add a node to the buffer with the garbage flag, so that it will be
1468+
* destroyed and freed when the scan is complete. */
14121469
static void gc_add_garbage(zend_refcounted *ref)
14131470
{
14141471
uint32_t idx;
@@ -1434,6 +1491,7 @@ static void gc_add_garbage(zend_refcounted *ref)
14341491
GC_G(num_roots)++;
14351492
}
14361493

1494+
/* Traverse the reference graph from ref, marking any white nodes as garbage. */
14371495
static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *stack)
14381496
{
14391497
int count = 0;
@@ -1622,6 +1680,7 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta
16221680
return count;
16231681
}
16241682

1683+
/* Traverse the reference graph from all roots, marking white nodes as garbage. */
16251684
static int gc_collect_roots(uint32_t *flags, gc_stack *stack)
16261685
{
16271686
uint32_t idx, end;
@@ -1808,6 +1867,7 @@ static ZEND_COLD ZEND_NORETURN void gc_start_destructor_fiber_error(void)
18081867
zend_error_noreturn(E_ERROR, "Unable to start destructor fiber");
18091868
}
18101869

1870+
/* Call destructors for garbage in the buffer. */
18111871
static zend_always_inline zend_result gc_call_destructors(uint32_t idx, uint32_t end, zend_fiber *fiber)
18121872
{
18131873
gc_root_buffer *current;
@@ -1910,6 +1970,7 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end)
19101970
}
19111971
}
19121972

1973+
/* Perform a garbage collection run. The default implementation of gc_collect_cycles. */
19131974
ZEND_API int zend_gc_collect_cycles(void)
19141975
{
19151976
int total_count = 0;

Zend/zend_operators.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, const
215215

216216
static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n)
217217
{
218-
#if defined(HAVE_MEMRCHR) && !defined(i386)
218+
#if defined(HAVE_MEMRCHR) && !defined(__i386__)
219219
/* On x86 memrchr() doesn't use SSE/AVX, so inlined version is faster */
220220
return (const void*)memrchr(s, c, n);
221221
#else

0 commit comments

Comments
 (0)