Skip to content

Commit 4d7e401

Browse files
PurHurcursoragent
andauthored
php-in-php: MathCosh NestedJIT kernel → NestedJIT-safe PHP (#28446) (#28450)
Delete libc cosh(3) NestedJIT leaf (JitCoshKernel + phpc_cosh_kernel, 86 lines); CoshJitHelper inlines fdlibm e_cosh via expPositive; MathCosh always ensureBridge. Overflow gates on Inf identity only — float self-inequality NaN probes are always-true under NestedJIT (AOT cosh(1) previously collapsed to 0.5·e). Also prune orphan Shmop helper-runtime unit so prelink --strict stays green. Co-authored-by: PurHur <PurHur@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e71f760 commit 4d7e401

31 files changed

Lines changed: 709 additions & 566 deletions

File tree

docs/bootstrap-inventory.md

Lines changed: 415 additions & 428 deletions
Large diffs are not rendered by default.

docs/bootstrap-profile.json

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -663,9 +663,11 @@
663663
"ext/filter/filter_var.php",
664664
"ext/filter/filter_var_array.php",
665665
"ext/ftp/BuiltinClasses.php",
666+
"ext/ftp/FtpConnectJitHelper.php",
666667
"ext/ftp/FtpConstants.php",
667668
"ext/ftp/FtpExtensionPolicy.php",
668669
"ext/ftp/FtpSerializeDeny.php",
670+
"ext/ftp/JitFtpConnect.php",
669671
"ext/ftp/Module.php",
670672
"ext/ftp/VmFtpArg.php",
671673
"ext/ftp/VmFtpConnection.php",
@@ -2723,7 +2725,6 @@
27232725
"ext/standard/JitConvertUudecode.php",
27242726
"ext/standard/JitConvertUuencode.php",
27252727
"ext/standard/JitCopy.php",
2726-
"ext/standard/JitCoshKernel.php",
27272728
"ext/standard/JitCountChars.php",
27282729
"ext/standard/JitCrc32.php",
27292730
"ext/standard/JitCrc32c.php",
@@ -4310,7 +4311,6 @@
43104311
"ext/standard/phpc_clone_with_begin.php",
43114312
"ext/standard/phpc_clone_with_end.php",
43124313
"ext/standard/phpc_clone_with_reinit.php",
4313-
"ext/standard/phpc_cosh_kernel.php",
43144314
"ext/standard/phpc_deploy_path.php",
43154315
"ext/standard/phpc_destruct_try_invoke_native.php",
43164316
"ext/standard/phpc_expm1_kernel.php",
@@ -4672,8 +4672,17 @@
46724672
"ext/sysvsem/sem_get.php",
46734673
"ext/sysvsem/sem_release.php",
46744674
"ext/sysvsem/sem_remove.php",
4675+
"ext/sysvshm/JitShmopClose.php",
4676+
"ext/sysvshm/JitShmopDelete.php",
4677+
"ext/sysvshm/JitShmopHandle.php",
4678+
"ext/sysvshm/JitShmopOpen.php",
4679+
"ext/sysvshm/JitShmopRead.php",
4680+
"ext/sysvshm/JitShmopSize.php",
4681+
"ext/sysvshm/JitShmopWrite.php",
46754682
"ext/sysvshm/Module.php",
46764683
"ext/sysvshm/ShmopArgs.php",
4684+
"ext/sysvshm/ShmopJitHelper.php",
4685+
"ext/sysvshm/ShmopLibcThinAbi.php",
46774686
"ext/sysvshm/SysvIpcSerializeDeny.php",
46784687
"ext/sysvshm/SysvShmArgs.php",
46794688
"ext/sysvshm/VmShmop.php",
@@ -5406,6 +5415,7 @@
54065415
"lib/JIT/Builtin/FsDirRuntime.php",
54075416
"lib/JIT/Builtin/FsGlobVecRuntime.php",
54085417
"lib/JIT/Builtin/FtokRuntime.php",
5418+
"lib/JIT/Builtin/FtpConnectRuntime.php",
54095419
"lib/JIT/Builtin/FunctionExistsRuntime.php",
54105420
"lib/JIT/Builtin/FunctionStaticRuntime.php",
54115421
"lib/JIT/Builtin/GcCollectCyclesCollectRuntime.php",
@@ -5633,6 +5643,7 @@
56335643
"lib/JIT/Builtin/SessionUnset.php",
56345644
"lib/JIT/Builtin/SessionWriteClose.php",
56355645
"lib/JIT/Builtin/SettypeRuntime.php",
5646+
"lib/JIT/Builtin/ShmopRuntime.php",
56365647
"lib/JIT/Builtin/ShuffleRuntime.php",
56375648
"lib/JIT/Builtin/SilenceRuntime.php",
56385649
"lib/JIT/Builtin/SocketAtmarkRuntime.php",
@@ -5738,6 +5749,7 @@
57385749
"lib/JIT/Builtin/StringFsDirJit.php",
57395750
"lib/JIT/Builtin/StringFsGlob.php",
57405751
"lib/JIT/Builtin/StringFsGlobVecJit.php",
5752+
"lib/JIT/Builtin/StringFtpConnect.php",
57415753
"lib/JIT/Builtin/StringFunctionExists.php",
57425754
"lib/JIT/Builtin/StringGetClassMethods.php",
57435755
"lib/JIT/Builtin/StringGetClassVars.php",
@@ -5818,6 +5830,7 @@
58185830
"lib/JIT/Builtin/StringRename.php",
58195831
"lib/JIT/Builtin/StringRmdir.php",
58205832
"lib/JIT/Builtin/StringSerialize.php",
5833+
"lib/JIT/Builtin/StringShmop.php",
58215834
"lib/JIT/Builtin/StringSimilarText.php",
58225835
"lib/JIT/Builtin/StringSimilarTextJit.php",
58235836
"lib/JIT/Builtin/StringSocketAtmark.php",
@@ -7406,9 +7419,9 @@
74067419
"test/bootstrap-aot/lib_opcode/main.php"
74077420
],
74087421
"totals": {
7409-
"inventory_files": 7172,
7422+
"inventory_files": 7185,
74107423
"excluded": 0,
7411-
"eligible": 7172,
7424+
"eligible": 7185,
74127425
"aot_lint_targets": 113,
74137426
"aot_link_targets": 100,
74147427
"aot_link_lib_targets": 1

docs/capabilities.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,6 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
690690
| `phpc_clone_with_begin` | yes | yes | yes | standard | |
691691
| `phpc_clone_with_end` | yes | yes | yes | standard | |
692692
| `phpc_clone_with_reinit` | yes | yes | yes | standard | |
693-
| `phpc_cosh_kernel` | yes | yes | yes | standard | |
694693
| `phpc_deploy_path` | yes | yes | yes | standard | AOT PHPT |
695694
| `phpc_destruct_try_invoke_native` | yes | yes | yes | standard | |
696695
| `phpc_expm1_kernel` | yes | yes | yes | standard | |

docs/pages/capability-comparison.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ <h1>PHP capability comparison</h1>
6464
</article>
6565
<article>
6666
<div>Stdlib builtins</div>
67-
<strong>1083</strong> / 1185 full (VM+JIT+AOT)
67+
<strong>1082</strong> / 1184 full (VM+JIT+AOT)
6868
<p style="margin:0.35rem 0 0;font-size:0.88rem;color:var(--text-muted)">67 partial · 35 gaps</p>
6969
</article>
7070
<article>
@@ -157,7 +157,7 @@ <h2>Language constructs</h2>
157157
<tr data-support="full"><td><code>Built-in `LazyGhostTrait` marker (PHP 8.4 lazy objects)</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/6096">#6096</a></td></tr>
158158
<tr data-support="full"><td><code>Array/argument unpack `...$x`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/1361">#1361</a></td></tr>
159159
<tr data-support="full"><td><code>`__serialize` / `__unserialize` magic methods</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/1365">#1365</a></td></tr>
160-
<tr data-support="gap"><td><code>Multi-type catch `catch (A</code></td><td class="status-yes">yes</td><td class="">B $e)` / intersection `catch (A&amp;B $e)`</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>yes</td></tr>
160+
<tr data-support="gap"><td><code>Multi-type catch `catch (A</code></td><td class="status-yes">yes</td><td class="">B $e)` (union only; `A&amp;B` ParseError like Zend)</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>yes</td></tr>
161161
<tr data-support="full"><td><code>`try` / `catch` / `throw`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/57">#57</a></td></tr>
162162
<tr data-support="full"><td><code>throw expressions (PHP 8.0) — `throw` in expression context</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/3802">#3802</a></td></tr>
163163
<tr data-support="full"><td><code>readonly classes</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td><a href="https://github.com/PurHur/php-compiler/issues/1360">#1360</a></td></tr>
@@ -869,7 +869,6 @@ <h2>Stdlib builtins</h2>
869869
<tr data-support="full"><td><code>`phpc_clone_with_begin`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
870870
<tr data-support="full"><td><code>`phpc_clone_with_end`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
871871
<tr data-support="full"><td><code>`phpc_clone_with_reinit`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
872-
<tr data-support="full"><td><code>`phpc_cosh_kernel`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
873872
<tr data-support="full"><td><code>`phpc_deploy_path`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
874873
<tr data-support="full"><td><code>`phpc_destruct_try_invoke_native`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>
875874
<tr data-support="full"><td><code>`phpc_expm1_kernel`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td></td></tr>

ext/standard/CoshJitHelper.php

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,150 @@
55
namespace PHPCompiler\ext\standard;
66

77
/**
8-
* cosh() for compiled JIT/AOT modules (#15156, #27005, php-in-PHP).
8+
* cosh() for compiled JIT/AOT modules (#15156, #27005, #28446, php-in-PHP).
99
*
10-
* Kernel path: {@see phpc_cosh_kernel}; VM SSOT remains VmMath::cosh.
11-
* Calling VmMath::cosh / \cosh from this helper re-enters the MathCosh bridge under
12-
* NestedJIT and yields 0 under thin standalone AOT (#27005 — ceil/hypot/sqrt peer).
10+
* NestedJIT-safe fdlibm e_cosh.c shape with inlined exp (#28446 /
11+
* peer MathSinh #28418 / MathAtanh #28377 / MathExp #28241).
12+
* Avoid `\cosh` / {@see VmMath::cosh} — NestedJIT re-enters MathCosh bridge under thin AOT.
13+
* Avoid cross-class Exp helper call — NestedJIT stubs to 0 (#27017 / Hypot shape).
14+
* Avoid pack/unpack (#27496). Avoid unbounded while-loops (#27838).
15+
* Avoid abs ternary that zeros under NestedJIT — use sqrtPositive(num*num) (asin #28263).
1316
* php-src: ext/standard/math.c — PHP_FUNCTION(cosh)
1417
*/
1518
final class CoshJitHelper
1619
{
1720
public static function coshArgv(float $num): float
1821
{
19-
return \phpc_cosh_kernel($num);
22+
if ($num !== $num) {
23+
return $num;
24+
}
25+
$inf = 1.0e+308;
26+
$inf = $inf * $inf;
27+
if ($num === $inf || $num === -$inf) {
28+
return $inf;
29+
}
30+
if (0.0 === $num) {
31+
return 1.0;
32+
}
33+
34+
// |num| without ternary abs (NestedJIT zeros `$x < 0 ? -$x : $x` — asin #28263).
35+
$ax = self::sqrtPositive($num * $num);
36+
$ex = self::expPositive($ax);
37+
// NestedJIT: float self-inequality NaN probes are unreliable (always-true) and
38+
// forced the half-exp overflow path for finite args (#28446 AOT cosh(1)→0.5·e).
39+
// Use `=== $inf` only (Floor Inf probe / MathExp #28241).
40+
if ($ex === $inf) {
41+
// exp(|x|) overflowed; 0.5·exp(|x|) via half-exp stays finite near DBL_MAX (fdlibm).
42+
$half = self::expPositive(0.5 * $ax);
43+
44+
return 0.5 * $half * $half;
45+
}
46+
47+
// cosh(|x|) = 0.5 · (e^|x| + e^−|x|) (even — no sign restore).
48+
// Split reciprocal — keeps NestedJIT from folding the add/div shape oddly.
49+
$inv = 1.0 / $ex;
50+
51+
return 0.5 * ($ex + $inv);
52+
}
53+
54+
/**
55+
* NestedJIT-safe exp (inlined from {@see ExpJitHelper} / MathExp #28241).
56+
* Kept private — do not call ExpJitHelper from this helper unit.
57+
*/
58+
private static function expPositive(float $num): float
59+
{
60+
// Host PHP: NaN / ±Inf. NestedJIT: `$num !== $num` and `=== -$inf` are unreliable;
61+
// `=== $inf` still catches +Inf under NestedJIT (peer Floor Inf probe).
62+
if ($num !== $num) {
63+
return $num;
64+
}
65+
$inf = 1.0e+308;
66+
$inf = $inf * $inf;
67+
if ($num === $inf) {
68+
return $inf;
69+
}
70+
if ($num === -$inf) {
71+
return 0.0;
72+
}
73+
74+
$ln2 = 0.693147180559945309417;
75+
$invLn2 = 1.44269504088896340736;
76+
$k = $num * $invLn2;
77+
$n = (int) ($k + ($k >= 0.0 ? 0.5 : -0.5));
78+
$r = $num - $n * $ln2;
79+
80+
// exp(r) via nested Horner (20 terms; |r| ≤ ln2/2 after reduction).
81+
$y = 1.0;
82+
$y = 1.0 + $r * $y / 20.0;
83+
$y = 1.0 + $r * $y / 19.0;
84+
$y = 1.0 + $r * $y / 18.0;
85+
$y = 1.0 + $r * $y / 17.0;
86+
$y = 1.0 + $r * $y / 16.0;
87+
$y = 1.0 + $r * $y / 15.0;
88+
$y = 1.0 + $r * $y / 14.0;
89+
$y = 1.0 + $r * $y / 13.0;
90+
$y = 1.0 + $r * $y / 12.0;
91+
$y = 1.0 + $r * $y / 11.0;
92+
$y = 1.0 + $r * $y / 10.0;
93+
$y = 1.0 + $r * $y / 9.0;
94+
$y = 1.0 + $r * $y / 8.0;
95+
$y = 1.0 + $r * $y / 7.0;
96+
$y = 1.0 + $r * $y / 6.0;
97+
$y = 1.0 + $r * $y / 5.0;
98+
$y = 1.0 + $r * $y / 4.0;
99+
$y = 1.0 + $r * $y / 3.0;
100+
$y = 1.0 + $r * $y / 2.0;
101+
$y = 1.0 + $r * $y / 1.0;
102+
103+
$absN = $n;
104+
if ($n < 0) {
105+
$absN = -$n;
106+
}
107+
// Float doubling (not int shift) covers |n| up to 1024 without int overflow.
108+
$scale = 1.0;
109+
for ($i = 0; $i < $absN && $i < 1024; ++$i) {
110+
$scale = $scale + $scale;
111+
}
112+
if ($n < 0) {
113+
$scale = 1.0 / $scale;
114+
}
115+
116+
return $y * $scale;
117+
}
118+
119+
/**
120+
* NestedJIT-safe sqrt for non-negative finite args (inlined from {@see SqrtJitHelper} /
121+
* {@see SinhJitHelper}).
122+
*/
123+
private static function sqrtPositive(float $num): float
124+
{
125+
if (0.0 === $num) {
126+
return 0.0;
127+
}
128+
$x = $num;
129+
$scale = 1.0;
130+
for ($i = 0; $i < 600; ++$i) {
131+
if ($x >= 4.0) {
132+
$x *= 0.25;
133+
$scale *= 2.0;
134+
} elseif ($x > 0.0 && $x < 0.25) {
135+
$x *= 4.0;
136+
$scale *= 0.5;
137+
} else {
138+
break;
139+
}
140+
}
141+
142+
$y = 0.5 * ($x + 1.0);
143+
$y = 0.5 * ($y + $x / $y);
144+
$y = 0.5 * ($y + $x / $y);
145+
$y = 0.5 * ($y + $x / $y);
146+
$y = 0.5 * ($y + $x / $y);
147+
$y = 0.5 * ($y + $x / $y);
148+
$y = 0.5 * ($y + $x / $y);
149+
$y = 0.5 * ($y + $x / $y);
150+
$y = 0.5 * ($y + $x / $y);
151+
152+
return $y * $scale;
20153
}
21154
}

ext/standard/JitCoshKernel.php

Lines changed: 0 additions & 30 deletions
This file was deleted.

ext/standard/Module.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,6 @@ public function getFunctions(): array
683683
new phpc_access_kernel(),
684684
new phpc_fpow_kernel(),
685685
new phpc_nextafter_kernel(),
686-
new phpc_cosh_kernel(),
687686
new phpc_tanh_kernel(),
688687
new phpc_atan_kernel(),
689688
new phpc_atan2_kernel(),

ext/standard/phpc_cosh_kernel.php

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)