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
843 changes: 459 additions & 384 deletions docs/bootstrap-inventory.md

Large diffs are not rendered by default.

14 changes: 12 additions & 2 deletions docs/bootstrap-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@
"ext/dom/DocumentLoad.php",
"ext/dom/DocumentLoadHTML.php",
"ext/dom/DocumentLoadXML.php",
"ext/dom/DocumentRegisterNodeClass.php",
"ext/dom/DocumentSaveHTML.php",
"ext/dom/DocumentSaveHTMLFile.php",
"ext/dom/DocumentSaveXML.php",
"ext/dom/DomClassConstants.php",
"ext/dom/DomClassMethod.php",
"ext/dom/DomConstants.php",
"ext/dom/DomDocumentPropertySupport.php",
"ext/dom/DomExceptionConstants.php",
"ext/dom/DomNodePropertySupport.php",
"ext/dom/DomNodeState.php",
"ext/dom/DomRegistry.php",
Expand Down Expand Up @@ -360,6 +362,7 @@
"ext/openssl/OpensslFunction.php",
"ext/openssl/VmOpenssl.php",
"ext/openssl/VmOpensslObjects.php",
"ext/openssl/VmOpensslSignNative.php",
"ext/openssl/VmOpensslX509Native.php",
"ext/openssl/openssl_cipher_iv_length.php",
"ext/openssl/openssl_cipher_key_length.php",
Expand All @@ -371,6 +374,7 @@
"ext/openssl/openssl_get_md_methods.php",
"ext/openssl/openssl_pkey_new.php",
"ext/openssl/openssl_sign.php",
"ext/openssl/openssl_verify.php",
"ext/openssl/openssl_x509_read.php",
"ext/posix/JitPosix.php",
"ext/posix/JitPosixTimes.php",
Expand Down Expand Up @@ -572,6 +576,7 @@
"ext/standard/CharInMaskJitHelper.php",
"ext/standard/CheckdateJitHelper.php",
"ext/standard/CheckdnsrrJitHelper.php",
"ext/standard/ChmodJitHelper.php",
"ext/standard/ChownJitHelper.php",
"ext/standard/ChunkSplitJitHelper.php",
"ext/standard/CliArgvJitHelper.php",
Expand Down Expand Up @@ -1163,6 +1168,7 @@
"ext/standard/ParseIniEngine.php",
"ext/standard/ParseStrEngine.php",
"ext/standard/ParseStrJitHelper.php",
"ext/standard/ParseStrNativeJitHelper.php",
"ext/standard/ParseUrlJitHelper.php",
"ext/standard/PasswordJitHelper.php",
"ext/standard/PathJitHelper.php",
Expand Down Expand Up @@ -2654,6 +2660,7 @@
"lib/JIT/Builtin/EmbedObOutput.php",
"lib/JIT/Builtin/EnumCasesRuntime.php",
"lib/JIT/Builtin/EnvLocalRuntime.php",
"lib/JIT/Builtin/EnvironMirrorUserScriptLlvm.php",
"lib/JIT/Builtin/ErrorHandler.php",
"lib/JIT/Builtin/ErrorHandlerJitRuntime.php",
"lib/JIT/Builtin/ErrorHandlerOutput.php",
Expand Down Expand Up @@ -2896,6 +2903,7 @@
"lib/JIT/Builtin/StringBitwiseNot.php",
"lib/JIT/Builtin/StringBz2.php",
"lib/JIT/Builtin/StringCaseCompare.php",
"lib/JIT/Builtin/StringChmod.php",
"lib/JIT/Builtin/StringChunkSplit.php",
"lib/JIT/Builtin/StringClockGettime.php",
"lib/JIT/Builtin/StringClockGettimeRuntime.php",
Expand Down Expand Up @@ -2947,6 +2955,8 @@
"lib/JIT/Builtin/StringHrtimeRuntime.php",
"lib/JIT/Builtin/StringHtmlspecialchars.php",
"lib/JIT/Builtin/StringHtmlspecialcharsDecode.php",
"lib/JIT/Builtin/StringHtmlspecialcharsStandaloneLlvm.php",
"lib/JIT/Builtin/StringHtmlspecialcharsUserScriptLlvm.php",
"lib/JIT/Builtin/StringHttpBuildQuery.php",
"lib/JIT/Builtin/StringIdate.php",
"lib/JIT/Builtin/StringImageTypeToExtension.php",
Expand Down Expand Up @@ -4061,9 +4071,9 @@
"test/bootstrap-aot/lib_opcode/main.php"
],
"totals": {
"inventory_files": 3831,
"inventory_files": 3841,
"excluded": 0,
"eligible": 3831,
"eligible": 3841,
"aot_lint_targets": 111,
"aot_link_targets": 98,
"aot_link_lib_targets": 1
Expand Down
24 changes: 24 additions & 0 deletions ext/standard/ChmodJitHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

/**
* chmod() for compiled JIT/AOT modules (#15458, php-in-PHP).
*
* SSOT: {@see VmFs::chmod()}
* php-src: ext/standard/filestat.c — php_chmod
*/
final class ChmodJitHelper
{
public static function invokeArgv(string $path, int $mode): bool
{
$ok = VmFs::chmod($path, $mode);
if (!$ok) {
TriggerErrorJitHelper::warning('chmod(): No such file or directory');
}

return $ok;
}
}
62 changes: 7 additions & 55 deletions ext/standard/JitChmod.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,21 @@

declare(strict_types=1);

/**
* JIT/AOT helper for chmod() via ChmodJitHelper PHP (#15458).
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Builtin\StringTriggerErrorJit;
use PHPCompiler\JIT\Builtin\StringChmod;
use PHPCompiler\JIT\Context;
use PHPCompiler\VM\ErrorReporter;
use PHPLLVM\Builder;
use PHPLLVM\Value;

/** LLVM lowering for chmod() via libc chmod(2). */
final class JitChmod
{
private static int $blockSerial = 0;

/** @return Value
* true when chmod(2) returns 0 */
/** @return Value */
public static function invoke(Context $context, Value $pathStr, Value $modeI32): Value
{
StringTriggerErrorJit::implement($context);
$map = $context->structFieldMap['__string__'];
$pathPtr = $context->builder->structGep($pathStr, $map['value']);
$i32 = $context->getTypeFromString('int32');
$ret = $context->builder->call(
$context->lookupFunction('chmod'),
$pathPtr,
$modeI32
);
$zero = $i32->constInt(0, false);
$failed = $context->builder->icmp(Builder::INT_NE, $ret, $zero);

$id = (string) (++self::$blockSerial);
$failBlock = BasicBlockHelper::append($context, 'chmod_fail_'.$id);
$okBlock = BasicBlockHelper::append($context, 'chmod_ok_'.$id);
$doneBlock = BasicBlockHelper::append($context, 'chmod_done_'.$id);
$context->builder->branchIf($failed, $failBlock, $okBlock);

$context->builder->positionAtEnd($failBlock);
self::emitWarning($context, 'chmod(): No such file or directory');
$context->builder->branch($doneBlock);

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

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

return $context->builder->icmp(Builder::INT_EQ, $ret, $zero);
}

private static function emitWarning(Context $context, string $message): void
{
$i8p = $context->getTypeFromString('int8*');
$sizeT = $context->getTypeFromString('size_t');
$i32 = $context->getTypeFromString('int32');
$msgPtr = $context->builder->pointerCast($context->constantFromString($message), $i8p);
$msgLen = $sizeT->constInt(\strlen($message), false);
$emptyFile = $context->builder->pointerCast($context->constantFromString(''), $i8p);
$context->builder->call(
$context->lookupFunction('__compiler_trigger_error'),
$msgPtr,
$msgLen,
$i32->constInt(ErrorReporter::E_WARNING, false),
$emptyFile,
$i32->constInt(0, false)
);
return StringChmod::invoke($context, $pathStr, $modeI32);
}
}
2 changes: 1 addition & 1 deletion ext/standard/chmod_.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/** chmod() — VM via VmFs; JIT/AOT via libc chmod(2). */
/** chmod() — VM via VmFs; JIT/AOT via ChmodJitHelper PHP (#15458). */
final class chmod_ extends Internal
{
public function __construct()
Expand Down
81 changes: 81 additions & 0 deletions lib/JIT/Builtin/StringChmod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\JIT\Builtin;

use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitNestedHelperCoerce;
use PHPCompiler\JIT\JitVmHelperLink;
use PHPLLVM\Value;

/**
* JIT/AOT link for chmod() via ChmodJitHelper PHP (#15458).
*
* Replaces libc chmod(2) LLVM in ext/standard/JitChmod.php.
* SSOT: {@see \PHPCompiler\ext\standard\VmFs::chmod()}.
* php-src: ext/standard/filestat.c — php_chmod
*/
final class StringChmod
{
private const ABI = '__phpc_jit_chmod';

private const HELPER_PATH = '/ext/standard/ChmodJitHelper.php';

private const INVOKE_HELPER = 'PHPCompiler\\ext\\standard\\ChmodJitHelper::invokeArgv';

/** @var list<string> */
private const COMPILED_HELPERS = [
self::INVOKE_HELPER,
];

public static function ensureLinked(Context $context): void
{
self::implement($context);
}

public static function ensureStandaloneBodies(Context $context): void
{
self::ensureLinked($context);
}

public static function invoke(Context $context, Value $path, Value $mode): Value
{
self::ensureLinked($context);

return $context->builder->call($context->lookupFunction(self::ABI), $path, $mode);
}

private static function implement(Context $context): void
{
$probe = $context->module->getNamedFunction(self::ABI);
if (null !== $probe && $probe->countBasicBlocks() > 0) {
$context->registerFunction(self::ABI, $probe);

return;
}

JitVmHelperLink::ensureCompiled($context, self::HELPER_PATH, self::COMPILED_HELPERS, '#15458');

$strPtr = $context->getTypeFromString('__string__*');
$i32 = $context->getTypeFromString('int32');
$i1 = $context->getTypeFromString('int1');
$fn = null !== $probe
? $probe
: $context->module->addFunction(
self::ABI,
$context->context->functionType($i1, false, $strPtr, $i32)
);

$entry = $fn->appendBasicBlock('chmod_bridge_entry');
$context->builder->positionAtEnd($entry);

$helperFn = JitVmHelperLink::lookupCompiled($context, self::INVOKE_HELPER, '#15458');
$raw = JitNestedHelperCoerce::callHelper($context, $helperFn, [$fn->getParam(0), $fn->getParam(1)]);
$bool = JitNestedHelperCoerce::coerceHelperScalarResult($context, $raw, $i1);
$context->builder->returnValue($bool);

$context->registerFunction(self::ABI, $fn);
$context->builder->clearInsertionPosition();
}
}
2 changes: 1 addition & 1 deletion test/compliance/cases/stdlib/chmod_jit.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
JIT: chmod() via libc chmod(2)
JIT: chmod() via ChmodJitHelper PHP (#15458)
--FILE--
<?php
$path = 'test/compliance/cases/stdlib/chmod_fixture/jit_data.txt';
Expand Down
2 changes: 2 additions & 0 deletions test/selfhost/compiler_lib_spine_smoke/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,7 @@
require_once __DIR__.'/../../../ext/standard/JitCheckdate.php';
require_once __DIR__.'/../../../ext/standard/JitCheckdnsrr.php';
require_once __DIR__.'/../../../ext/standard/JitChgrp.php';
require_once __DIR__.'/../../../ext/standard/ChmodJitHelper.php';
require_once __DIR__.'/../../../ext/standard/JitChmod.php';
require_once __DIR__.'/../../../ext/standard/JitChown.php';
require_once __DIR__.'/../../../ext/standard/JitChr.php';
Expand Down Expand Up @@ -2907,6 +2908,7 @@
require_once __DIR__.'/../../../lib/JIT/Builtin/StringImageTypeToExtension.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringBitwiseNot.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringBz2.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringChmod.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringClockGettime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringClockGettimeRuntime.php';
require_once __DIR__.'/../../../lib/JIT/Builtin/StringConvertUu.php';
Expand Down
1 change: 1 addition & 0 deletions test/unit/BootstrapSelfhostBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ final class BootstrapSelfhostBundleTest extends TestCase
'ext/standard/JitCrcCore.php',
'ext/standard/JitCrc32.php',
'ext/standard/JitExplode.php',
'ext/standard/ChmodJitHelper.php',
'ext/standard/JitChmod.php',
'ext/standard/JitCopy.php',
'ext/standard/JitDate.php',
Expand Down
45 changes: 45 additions & 0 deletions test/unit/ChmodRuntimeShrinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\Test\Unit;

use PHPCompiler\ext\standard\ChmodJitHelper;
use PHPCompiler\ext\standard\VmFs;
use PHPUnit\Framework\TestCase;

/** chmod() JIT routes through ChmodJitHelper PHP not libc chmod LLVM (#15458). */
final class ChmodRuntimeShrinkTest extends TestCase
{
public function testJitChmodUsesPhpBridgeNotLibc(): void
{
$source = (string) file_get_contents(__DIR__.'/../../ext/standard/JitChmod.php');
$this->assertStringContainsString('StringChmod::invoke', $source);
$this->assertStringNotContainsString("lookupFunction('chmod')", $source);
$this->assertStringNotContainsString('__compiler_trigger_error', $source);
}

public function testStringChmodBridgeUsesChmodJitHelper(): void
{
$bridge = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/StringChmod.php');
$this->assertStringContainsString('ChmodJitHelper', $bridge);
$this->assertStringNotContainsString("lookupFunction('chmod')", $bridge);
}

public function testChmodJitHelperDelegatesToVmFs(): void
{
$file = sys_get_temp_dir().'/phpc-chmod-'.bin2hex(random_bytes(4)).'.tmp';
$this->assertNotFalse(file_put_contents($file, 'x'));
$this->assertTrue(ChmodJitHelper::invokeArgv($file, 0644));
$this->assertSame(VmFs::chmod($file, 0600), ChmodJitHelper::invokeArgv($file, 0600));
$this->assertFalse(ChmodJitHelper::invokeArgv($file.'/missing-15458', 0644));
unlink($file);
}

public function testSpineBundleIncludesChmodJitHelper(): void
{
$spine = (string) file_get_contents(__DIR__.'/../../test/selfhost/compiler_lib_spine_smoke/main.php');
$this->assertStringContainsString('ChmodJitHelper.php', $spine);
$this->assertStringContainsString('StringChmod.php', $spine);
}
}