diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index a43a3526..36348c2b 100644 --- a/docs/bootstrap-inventory.md +++ b/docs/bootstrap-inventory.md @@ -8,9 +8,9 @@ Regenerate: `php script/bootstrap-inventory.php` | Metric | Count | |--------|------:| -| PHP files on vm.php path | 239 | +| PHP files on vm.php path | 240 | | Source constructs flagged (blockers) | 10 | -| Source constructs flagged (warnings) | 628 | +| Source constructs flagged (warnings) | 629 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -37,6 +37,7 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: | `ext/standard/JitDate.php` | 0 | 1 | | `ext/standard/JitEnv.php` | 0 | 1 | | `ext/standard/JitExplode.php` | 0 | 1 | +| `ext/standard/JitGetallheaders.php` | 0 | 1 | | `ext/standard/JitHeader.php` | 0 | 1 | | `ext/standard/JitHex2bin.php` | 0 | 1 | | `ext/standard/JitHtmlspecialchars.php` | 0 | 1 | @@ -292,6 +293,11 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: **Warnings** (review for bootstrap subset): - 1 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler +### `ext/standard/JitGetallheaders.php` + +**Warnings** (review for bootstrap subset): +- 1 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + ### `ext/standard/JitHeader.php` **Warnings** (review for bootstrap subset): @@ -1301,10 +1307,10 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: - new JIT\Call\Native (line 149) - new ext\standard\boolval (line 268) - new Variable (line 432) -- new Variable (line 813) -- new Operand\Literal (line 883) -- new Operand\Literal (line 887) +- new Variable (line 821) - new Operand\Literal (line 891) +- new Operand\Literal (line 895) +- new Operand\Literal (line 899) - 12 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler ### `lib/JIT/Analyzer.php` diff --git a/docs/bootstrap-profile.json b/docs/bootstrap-profile.json index 1234852c..791ec03a 100644 --- a/docs/bootstrap-profile.json +++ b/docs/bootstrap-profile.json @@ -35,6 +35,7 @@ "ext/standard/JitDate.php", "ext/standard/JitEnv.php", "ext/standard/JitExplode.php", + "ext/standard/JitGetallheaders.php", "ext/standard/JitHeader.php", "ext/standard/JitHex2bin.php", "ext/standard/JitHtmlspecialchars.php", @@ -273,9 +274,9 @@ "test/bootstrap-aot/echo_hello.php" ], "totals": { - "inventory_files": 239, + "inventory_files": 240, "excluded": 2, - "eligible": 237, + "eligible": 238, "aot_lint_targets": 2 } } diff --git a/docs/capabilities.md b/docs/capabilities.md index 36cce544..782c0597 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -8,7 +8,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `array_combine` | yes | no | no | standard | doc: VM only; not implemented for JIT in this compiler build | | `array_fill` | yes | yes | yes | standard | JIT PHPT | | `array_flip` | yes | no | no | standard | doc: VM only; not implemented for JIT in this compiler build | -| `array_key_exists` | yes | yes | yes | standard | AOT PHPT | +| `array_key_exists` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `array_keys` | yes | yes | yes | standard | doc: VM only | | `array_merge` | yes | yes | yes | standard | doc: VM only | | `array_pop` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | @@ -42,7 +42,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `floatval` | yes | yes | yes | standard | | | `floor` | yes | yes | yes | standard | | | `fmod` | yes | yes | yes | standard | | -| `getallheaders` | yes | no | no | standard | doc: VM only; not implemented for JIT in this compiler build | +| `getallheaders` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `getenv` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `gettype` | yes | yes | yes | standard | | | `glob` | yes | yes | yes | standard | | diff --git a/ext/standard/JitGetallheaders.php b/ext/standard/JitGetallheaders.php new file mode 100644 index 00000000..ad57266a --- /dev/null +++ b/ext/standard/JitGetallheaders.php @@ -0,0 +1,75 @@ +helper->loadValue($serverVar); + + $vmServer = $context->runtime->vmContext->getSuperglobal('_SERVER'); + if (null === $vmServer || VMVariable::TYPE_ARRAY !== $vmServer->type) { + return $result; + } + $table = $vmServer->toArray(); + if (!$table instanceof HashTable) { + return $result; + } + + foreach ($table->iterateKeyed(true) as [$keyVar, $valueVar]) { + if (VMVariable::TYPE_STRING !== $keyVar->type) { + continue; + } + $serverKey = $keyVar->toString(); + $headerName = Superglobals::serverKeyToHeaderName($serverKey); + if (null === $headerName) { + continue; + } + $resolved = $valueVar->resolveIndirect(); + if (VMVariable::TYPE_STRING !== $resolved->type) { + continue; + } + + $serverKeyStr = $context->builder->load( + $context->constantStringFromString($serverKey) + ); + $headerKeyStr = $context->builder->load( + $context->constantStringFromString($headerName) + ); + $valueBox = $context->builder->call( + $context->lookupFunction('__hashtable__readStringKeyValue'), + $serverPtr, + $serverKeyStr + ); + $valueStr = $context->builder->call( + $context->lookupFunction('__value__readString'), + $valueBox + ); + $context->builder->call( + $context->lookupFunction('__hashtable__setStringKeyString'), + $result, + $headerKeyStr, + $valueStr + ); + } + + return $result; + } +} diff --git a/ext/standard/getallheaders_.php b/ext/standard/getallheaders_.php index b0d9a9dd..fd7b6c3d 100644 --- a/ext/standard/getallheaders_.php +++ b/ext/standard/getallheaders_.php @@ -14,7 +14,7 @@ use PHPLLVM\Value; /** - * getallheaders() — request headers from $_SERVER HTTP_* entries (VM only; issue #307). + * getallheaders() — request headers from $_SERVER HTTP_* entries (issue #307). */ final class getallheaders_ extends Internal { @@ -40,6 +40,10 @@ public function execute(Frame $frame): void public function call(Context $context, JITVariable ...$args): Value { - throw new \LogicException('getallheaders() is not implemented for JIT in this compiler build'); + if (\count($args) > 0) { + throw new \LogicException('getallheaders() takes no arguments'); + } + + return JitGetallheaders::invoke($context); } } diff --git a/lib/JIT.php b/lib/JIT.php index 27f524e6..ce3fcbf3 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -755,6 +755,14 @@ private function assignOperand(Operand $result, Variable $value): void { $owned ); + return; + case Variable::TYPE_HASHTABLE: + $this->context->builder->call( + $this->context->lookupFunction('__value__writeHashtable'), + $valueRef, + $this->context->helper->loadValue($value) + ); + return; case Variable::TYPE_VALUE: $loaded = $this->context->builder->load($this->context->helper->loadValue($value)); diff --git a/test/compliance/cases/stdlib/getallheaders_jit.phpt b/test/compliance/cases/stdlib/getallheaders_jit.phpt new file mode 100644 index 00000000..a6667c00 --- /dev/null +++ b/test/compliance/cases/stdlib/getallheaders_jit.phpt @@ -0,0 +1,14 @@ +--TEST-- +stdlib getallheaders() JIT from CGI HTTP_* environment (issue #307) +--ENV-- +REQUEST_METHOD=GET +HTTP_X_TEST=1 +HTTP_HOST=example.test +--FILE-- +