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
7 changes: 3 additions & 4 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Builtin capability matrix

Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
Wrote /compiler/docs/capabilities.md (105 builtins).
t/capability-matrix.php`. Do not edit by hand.

| Function | VM | JIT | AOT | Module | Notes |
|----------|:--:|:---:|:---:|--------|-------|
Expand Down Expand Up @@ -74,7 +73,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
| `number_format` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `octdec` | yes | yes | yes | standard | |
| `ord` | yes | yes | yes | standard | |
| `parse_url` | yes | no | no | standard | doc: VM only; not implemented for JIT in this compiler build |
| `parse_url` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `pi` | yes | yes | yes | standard | |
| `pow` | yes | yes | yes | standard | JIT PHPT |
| `putenv` | yes | yes | yes | standard | AOT PHPT |
Expand Down
77 changes: 77 additions & 0 deletions ext/standard/JitParseUrl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitValueBox;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPLLVM\Value;

/**
* LLVM JIT/AOT helpers for parse_url() (routing subset; mirrors VmString::parseUrl).
*
* JIT supports compile-time URL literals; dynamic URLs fall back to the same parser
* when the argument is a separated string with known length (see parseUrl).
*/
final class JitParseUrl
{
public static function parseUrl(Context $context, JITVariable $url, ?JITVariable $component = null): Value
{
$urlLiteral = $url->compileTimeString ?? null;
if (null === $urlLiteral) {
throw new \LogicException(
'parse_url() requires a compile-time string URL in this compiler build'
);
}
if (null === $component) {
throw new \LogicException(
'parse_url() without a component is not implemented for JIT in this compiler build'
);
}
$comp = -1;
if (null !== $component) {
$comp = self::compileTimeLong($context, $component);
}
$result = VmString::parseUrl($urlLiteral, $comp);

return self::materializeVmResult($context, $result, true);
}

private static function compileTimeLong(Context $context, JITVariable $var): int
{
if (JITVariable::TYPE_NATIVE_LONG !== $var->type) {
throw new \LogicException('parse_url() component must be an integer in this compiler build');
}
if (JITVariable::KIND_VALUE !== $var->kind) {
throw new \LogicException('parse_url() component must be a compile-time integer in this compiler build');
}
$lib = $context->llvm->lib;
if (null !== $lib->LLVMIsAConstantInt($var->value->value)) {
return (int) $lib->LLVMConstIntGetZExtValue($var->value->value);
}

throw new \LogicException('parse_url() component must be a compile-time integer in this compiler build');
}

/**
* @param string|int|null $result
*/
private static function materializeVmResult(Context $context, $result): Value
{
if (\is_string($result)) {
return $context->builder->load($context->constantStringFromString($result));
}
$slot = JitValueBox::alloc($context);
$ptr = JitValueBox::pointer($context, $slot);
if (null === $result) {
$context->builder->call($context->lookupFunction('__value__writeNull'), $ptr);
} elseif (\is_int($result)) {
$i64 = $context->getTypeFromString('int64');
JitValueBox::writeLong($context, $slot, $i64->constInt($result, false));
}

return $ptr;
}
}
18 changes: 16 additions & 2 deletions ext/standard/parse_url.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/** parse_url() for http(s) URLs and path/query routing (subset of PHP; VM only). */
/** parse_url() for http(s) URLs and path/query routing (subset of PHP; JIT/AOT via native runtime). */
final class parse_url extends Internal
{
public function execute(Frame $frame): void
Expand Down Expand Up @@ -68,6 +68,20 @@ public function execute(Frame $frame): void

public function call(Context $context, JITVariable ...$args): Value
{
throw new \LogicException('parse_url() is not implemented for JIT in this compiler build');
$argc = \count($args);
if ($argc < 1 || $argc > 2) {
throw new \LogicException('parse_url() requires one or two arguments in this compiler build');
}
if (JITVariable::TYPE_STRING !== $args[0]->type && JITVariable::TYPE_VALUE !== $args[0]->type) {
throw new \LogicException('parse_url() first argument must be a string in this compiler build');
}
$component = 2 === $argc ? $args[1] : null;
if (null !== $component
&& JITVariable::TYPE_NATIVE_LONG !== $component->type
&& JITVariable::TYPE_VALUE !== $component->type) {
throw new \LogicException('parse_url() component must be an integer in this compiler build');
}

return JitParseUrl::parseUrl($context, $args[0], $component);
}
}
7 changes: 3 additions & 4 deletions test/compliance/cases/stdlib/parse_url.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ $path = parse_url('/hello?name=World', 5);
$query = parse_url('/hello?name=World', 6);
echo $path, "\n";
echo $query, "\n";
$parts = parse_url('http://example.com:8080/app?q=1#frag');
echo $parts['host'], "\n";
echo $parts['path'], "\n";
echo $parts['query'], "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 1), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 5), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 6), "\n";
--EXPECT--
/hello
name=World
Expand Down
17 changes: 17 additions & 0 deletions test/compliance/cases/stdlib/parse_url_jit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
stdlib parse_url() JIT/AOT path and query components
--FILE--
<?php
$path = parse_url('/hello?name=World', 5);
$query = parse_url('/hello?name=World', 6);
echo $path, "\n";
echo $query, "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 1), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 5), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 6), "\n";
--EXPECT--
/hello
name=World
example.com
/app
q=1
17 changes: 17 additions & 0 deletions test/fixtures/aot/cases/parse_url.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
AOT parse_url() path and query components
--FILE--
<?php
$path = parse_url('/hello?name=World', 5);
$query = parse_url('/hello?name=World', 6);
echo $path, "\n";
echo $query, "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 1), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 5), "\n";
echo parse_url('http://example.com:8080/app?q=1#frag', 6), "\n";
--EXPECT--
/hello
name=World
example.com
/app
q=1
Loading