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
40 changes: 40 additions & 0 deletions ext/standard/JitIncludePath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\Builtin\IncludePathRuntime;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitValueBox;
use PHPLLVM\Value;

/** LLVM lowering for get/set/restore_include_path (issues #3223, #6051). */
final class JitIncludePath
{
public static function get(Context $context): Value
{
IncludePathRuntime::ensureLinked($context);
$slot = JitValueBox::alloc($context);
$ptr = JitValueBox::pointer($context, $slot);
$context->builder->call($context->lookupFunction('__compiler_get_include_path'), $ptr);

return $ptr;
}

public static function set(Context $context, Value $newPath): Value
{
IncludePathRuntime::ensureLinked($context);
$slot = JitValueBox::alloc($context);
$ptr = JitValueBox::pointer($context, $slot);
$context->builder->call($context->lookupFunction('__compiler_set_include_path'), $newPath, $ptr);

return $ptr;
}

public static function restore(Context $context): void
{
IncludePathRuntime::ensureLinked($context);
$context->builder->call($context->lookupFunction('__compiler_restore_include_path'));
}
}
46 changes: 46 additions & 0 deletions ext/standard/JitResolveIncludePath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Builtin\IncludePathRuntime;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitValueBox;
use PHPLLVM\Builder;
use PHPLLVM\Value;

/** LLVM lowering for stream_resolve_include_path() (issue #6051). */
final class JitResolveIncludePath
{
public static function invoke(Context $context, Value $filename): Value
{
IncludePathRuntime::ensureLinked($context);
$resolved = $context->builder->call(
$context->lookupFunction('__compiler_stream_resolve_include_path'),
$filename
);
$strPtrTy = $context->getTypeFromString('__string__*');
$isFalse = $context->builder->icmp(Builder::INT_EQ, $resolved, $strPtrTy->constNull());
$slot = JitValueBox::alloc($context);
$ptr = JitValueBox::pointer($context, $slot);
$failBlock = BasicBlockHelper::append($context, 'resolve_inc_fail');
$okBlock = BasicBlockHelper::append($context, 'resolve_inc_ok');
$doneBlock = BasicBlockHelper::append($context, 'resolve_inc_done');
$context->builder->branchIf($isFalse, $failBlock, $okBlock);

$context->builder->positionAtEnd($failBlock);
$i1 = $context->getTypeFromString('int1');
JitValueBox::writeBool($context, $slot, $i1->constInt(0, false));
$context->builder->branch($doneBlock);

$context->builder->positionAtEnd($okBlock);
$context->builder->call($context->lookupFunction('__value__writeString'), $ptr, $resolved);
$context->builder->branch($doneBlock);

$context->builder->positionAtEnd($doneBlock);

return $ptr;
}
}
4 changes: 4 additions & 0 deletions ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,10 @@ public function getFunctions(): array
new tempnam(),
new tmpfile(),
new getcwd_(),
new get_include_path(),
new set_include_path(),
new restore_include_path(),
new stream_resolve_include_path(),
new gethostname(),
new gethostbynamel(),
new gethostbyname(),
Expand Down
33 changes: 33 additions & 0 deletions ext/standard/VmFs.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace PHPCompiler\ext\standard;

use PHPCompiler\VM\HashTable;
use PHPCompiler\VM\ScriptStack;
use PHPCompiler\VM\Variable;

/** Host filesystem helpers for stdlib builtins (VM). */
Expand Down Expand Up @@ -453,6 +454,38 @@ public static function fileGetContents(string $path) {
return $data;
}

/**
* stream_resolve_include_path() — search include_path for filename (ext/standard/streams.c; #6051).
*
* @return string|false absolute path when found
*/
public static function resolveIncludePath(string $filename): string|false
{
if ('' === $filename || str_contains($filename, "\0")) {
return false;
}
if ($filename[0] === '/' || (\strlen($filename) > 1 && $filename[1] === ':')) {
$normalized = ScriptStack::normalize($filename);

return '' !== $normalized && \is_file($normalized) ? $normalized : false;
}
$includePath = VmIncludePath::get();
if ('' === $includePath) {
return false;
}
foreach (\explode(\PATH_SEPARATOR, $includePath) as $dir) {
if ('' === $dir) {
continue;
}
$candidate = ScriptStack::normalize(\rtrim($dir, '/\\').'/'.$filename);
if ('' !== $candidate && \is_file($candidate)) {
return $candidate;
}
}

return false;
}

/**
* @return list<string>|false
*/
Expand Down
47 changes: 47 additions & 0 deletions ext/standard/VmIncludePath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

/**
* include_path stack (php-src PG(include_path) / zend_ini; issues #3223, #6051).
*
* Default matches Zend: ".". {@see set_include_path()} replaces the active entry;
* {@see restore_include_path()} pops the saved stack.
*/
final class VmIncludePath
{
/** @var list<string> */
private static array $stack = ['.'];

public static function get(): string
{
return self::$stack[\count(self::$stack) - 1];
}

/** @return string previous include_path */
public static function set(string $newPath): string
{
$old = self::get();
self::$stack[\count(self::$stack) - 1] = $newPath;

return $old;
}

public static function restore(): void
{
if (\count(self::$stack) > 1) {
\array_pop(self::$stack);
}
}

/** Push a new include_path while preserving the previous value on the stack. */
public static function push(string $newPath): string
{
$old = self::get();
self::$stack[] = $newPath;

return $old;
}
}
2 changes: 1 addition & 1 deletion ext/standard/VmMetaTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class VmMetaTags
*/
public static function getMetaTags(string $filename, bool $useIncludePath = false) {
if ($useIncludePath) {
$resolved = stream_resolve_include_path($filename);
$resolved = VmFs::resolveIncludePath($filename);
if (false !== $resolved) {
$filename = $resolved;
}
Expand Down
44 changes: 44 additions & 0 deletions ext/standard/get_include_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPLLVM\Value;

/** get_include_path() — active include_path (ext/standard/basic_functions.c; #3223). */
final class get_include_path extends Internal
{
public function __construct()
{
parent::__construct('get_include_path');
}

public function execute(Frame $frame): void
{
if (\count($frame->calledArgs) > 0) {
throw new \ArgumentCountError(
'get_include_path() expects exactly 0 arguments, '.\count($frame->calledArgs).' given'
);
}
if (null === $frame->returnVar) {
return;
}
$frame->returnVar->string(VmIncludePath::get());
}

public function call(Context $context, JITVariable ...$args): Value
{
if (\count($args) > 0) {
throw new \ArgumentCountError(
'get_include_path() expects exactly 0 arguments, '.\count($args).' given'
);
}

return JitIncludePath::get($context);
}
}
42 changes: 42 additions & 0 deletions ext/standard/restore_include_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPLLVM\Value;

/** restore_include_path() — pop include_path stack (ext/standard/basic_functions.c; #3223). */
final class restore_include_path extends Internal
{
public function __construct()
{
parent::__construct('restore_include_path');
}

public function execute(Frame $frame): void
{
if (\count($frame->calledArgs) > 0) {
throw new \ArgumentCountError(
'restore_include_path() expects exactly 0 arguments, '.\count($frame->calledArgs).' given'
);
}
VmIncludePath::restore();
}

public function call(Context $context, JITVariable ...$args): Value
{
if (\count($args) > 0) {
throw new \ArgumentCountError(
'restore_include_path() expects exactly 0 arguments, '.\count($args).' given'
);
}
JitIncludePath::restore($context);

return $context->getTypeFromString('int32')->constInt(0, false);
}
}
59 changes: 59 additions & 0 deletions ext/standard/set_include_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitStringBuiltinArg;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPLLVM\Value;

/** set_include_path() — replace include_path (ext/standard/basic_functions.c; #3223). */
final class set_include_path extends Internal
{
public function __construct()
{
parent::__construct('set_include_path');
}

public function execute(Frame $frame): void
{
if (1 !== \count($frame->calledArgs)) {
throw new \ArgumentCountError(
'set_include_path() expects exactly 1 argument, '.\count($frame->calledArgs).' given'
);
}
if (null === $frame->returnVar) {
return;
}
$newPath = VmString::coerceStringBuiltinArg(
$frame->calledArgs[0],
'set_include_path',
0,
'new_include_path'
);
$old = VmIncludePath::push($newPath);
$frame->returnVar->string($old);
}

public function call(Context $context, JITVariable ...$args): Value
{
if (1 !== \count($args)) {
throw new \ArgumentCountError(
'set_include_path() expects exactly 1 argument, '.\count($args).' given'
);
}
$newPath = JitStringBuiltinArg::lower(
$context,
$args[0],
'set_include_path',
0,
'new_include_path'
);

return JitIncludePath::set($context, $newPath);
}
}
Loading