Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions docs/bootstrap-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ Regenerate: `php script/bootstrap-inventory.php`

| Metric | Count |
|--------|------:|
| PHP files on vm.php path | 8592 |
| Phase A inventory files (M2 ratio SSOT) | 8592 |
| PHP files on vm.php path | 8593 |
| Phase A inventory files (M2 ratio SSOT) | 8593 |
| Phase A ratio-deferred paths | 0 |
| Source constructs flagged (blockers) | 0 |
| Source constructs flagged (warnings) | 26785 |
| Source constructs flagged (warnings) | 26789 |

## Compiler CFG gaps (`lib/Compiler.php`)

Expand Down Expand Up @@ -7602,10 +7602,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
| `lib/JIT/UnserializeObjectDecodeLlvm.php` | 0 | 1 |
| `lib/JIT/UnsetHelper.php` | 0 | 1 |
| `lib/JIT/UnsetHelperLlvm.php` | 0 | 4 |
| `lib/JIT/UserCallableResolver.php` | 0 | 1 |
| `lib/JIT/UserScriptAotEnv.php` | 0 | 1 |
| `lib/JIT/UsortCallbackPolicy.php` | 0 | 1 |
| `lib/JIT/UsortKeyedLlvm.php` | 0 | 1 |
| `lib/JIT/UsortPackedLlvm.php` | 0 | 2 |
| `lib/JIT/UsortPackedLlvm.php` | 0 | 5 |
| `lib/JIT/ValueBoxDimWrite.php` | 0 | 1 |
| `lib/JIT/ValueEchoHelper.php` | 0 | 2 |
| `lib/JIT/ValueSortKeyedLlvm.php` | 0 | 2 |
Expand Down Expand Up @@ -51908,7 +51909,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/JIT/Builtin/ArrayMapRuntime.php`

**Warnings** (review for bootstrap subset):
- new JITVariable (line 405)
- new JITVariable (line 409)
- 26 class method(s)

### `lib/JIT/Builtin/ArrayMergeRecursiveRuntime.php`
Expand Down Expand Up @@ -62415,6 +62416,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
- 13 class method(s)
- 2 closure(s)

### `lib/JIT/UserCallableResolver.php`

**Warnings** (review for bootstrap subset):
- 1 class method(s)

### `lib/JIT/UserScriptAotEnv.php`

**Warnings** (review for bootstrap subset):
Expand All @@ -62433,8 +62439,11 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/JIT/UsortPackedLlvm.php`

**Warnings** (review for bootstrap subset):
- new NestedClosureInvoke (line 126)
- 4 class method(s)
- new Variable (line 43)
- new NestedClosureInvoke (line 46)
- new Variable (line 105)
- 9 class method(s)
- 5 closure(s)

### `lib/JIT/ValueBoxDimWrite.php`

Expand Down Expand Up @@ -62629,9 +62638,9 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag
### `lib/JIT/ZendSortLlvm.php`

**Warnings** (review for bootstrap subset):
- new self (line 57)
- new self (line 64)
- 17 class method(s)
- 3 closure(s)
- 4 closure(s)

### `lib/JIT/ZipExtensionHooks.php`

Expand Down
5 changes: 3 additions & 2 deletions docs/bootstrap-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -7694,6 +7694,7 @@
"lib/JIT/UnserializeObjectDecodeLlvm.php",
"lib/JIT/UnsetHelper.php",
"lib/JIT/UnsetHelperLlvm.php",
"lib/JIT/UserCallableResolver.php",
"lib/JIT/UserScriptAotEnv.php",
"lib/JIT/UsortCallbackPolicy.php",
"lib/JIT/UsortKeyedLlvm.php",
Expand Down Expand Up @@ -8826,9 +8827,9 @@
"test/bootstrap-aot/lib_opcode/main.php"
],
"totals": {
"inventory_files": 8592,
"inventory_files": 8593,
"excluded": 0,
"eligible": 8592,
"eligible": 8593,
"aot_lint_targets": 113,
"aot_link_targets": 100,
"aot_link_lib_targets": 1
Expand Down
4 changes: 4 additions & 0 deletions lib/JIT/Builtin/ArrayMapRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public static function mapSingle(Context $context, JITVariable $callback, JITVar
$callback->compileTimeString
)) {
$name = $callback->compileTimeString;
$userFn = \PHPCompiler\JIT\UserCallableResolver::userFunctionCall($context, $callback);
if (null !== $userFn) {
return ArrayMapLlvm::mapStaticMethod($context, $ht, $userFn);
}
if (null !== $name) {
return ArrayMapLlvm::mapBuiltin($context, $ht, $name);
}
Expand Down
7 changes: 7 additions & 0 deletions lib/JIT/Builtin/UsortRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ final class UsortRuntime

public static function usortPacked(Context $context, JITVariable $array, JITVariable $callback): Value
{
$userFn = \PHPCompiler\JIT\UserCallableResolver::userFunctionCall($context, $callback);
if (null !== $userFn && !ArrayBuiltinHelper::isNativeArray($array->type)) {
$ht = HashTableHelper::separateContainerForWrite($context, $array);
\PHPCompiler\JIT\UsortPackedLlvm::sortPackedWithFunction($context, $ht, $userFn);

return $context->getTypeFromString('int1')->constInt(1, false);
}
UsortCallbackPolicy::assertJitLowerable($context, $callback);
if (UsortCallbackPolicy::isClosureJitLowerable($callback)) {
self::sortPackedWithClosure($context, $array, $callback);
Expand Down
35 changes: 35 additions & 0 deletions lib/JIT/UserCallableResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\JIT;

/**
* Compile-time resolution of string callables that name a user function
* (`array_map('fmt', $xs)`, `usort($a, 'cmp')`).
*
* php-src resolves these through the function table at call time (zend_is_callable_ex);
* for a compile-time literal naming a function declared in this program the target is
* fixed, so callers can invoke its Native call directly. Builtin names are left to the
* existing builtin paths (a user function cannot shadow one — redeclaration is fatal).
*/
final class UserCallableResolver
{
public static function userFunctionCall(Context $context, Variable $callback): ?Call
{
$name = $callback->compileTimeString;
if (!\is_string($name) || '' === $name || str_contains($name, '::')) {
return null;
}
$lc = strtolower(ltrim($name, '\\'));
if (null !== \PHPCompiler\ext\standard\BuiltinRegistry::resolve($lc)) {
return null;
}
if (!$context->functionIsRegistered($lc)) {
return null;
}
$call = $context->resolveFunctionProxy($lc);

return $call instanceof Call\Native ? $call : null;
}
}
Loading
Loading