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
9 changes: 9 additions & 0 deletions lib/JIT.php
Original file line number Diff line number Diff line change
Expand Up @@ -12867,6 +12867,15 @@ private function assignOperandValue(Operand $result, PHPLLVM\Value $value, bool
}
$dest = $this->context->getVariableFromOp($result);
if ($dest->kind !== Variable::KIND_VARIABLE) {
if (Variable::KIND_VALUE === $dest->kind) {
// The temp was pre-bound as a folded value (defined()/class_exists()
// spine-guard folding registers NATIVE_BOOL KIND_VALUE bindings) and
// the real producer emits afterwards. assignOperand() rebinds these;
// mirror that here instead of dying mid-bundle (#16828).
$this->context->makeVariableFromValueOp($value, $result);

return;
}
throw new \LogicException('Cannot assign to a value');
}
$valueTy = $this->context->getStringFromType($value->typeOf());
Expand Down
6 changes: 6 additions & 0 deletions lib/VM.php
Original file line number Diff line number Diff line change
Expand Up @@ -4718,6 +4718,12 @@ private function runFramesInner(): int
$frame->scope[$op->arg1]->string($builtinFn);
break;
}
if ('self' !== strtolower($className) && 'static' !== strtolower($className)) {
// Foo::class is a pure name literal — Zend resolves it
// without the class being declared (#16828).
$frame->scope[$op->arg1]->string(ltrim($className, '\\'));
break;
}
}

return $this->raise("Unknown class for constant fetch: {$className}", $frame);
Expand Down
9 changes: 9 additions & 0 deletions lib/VM/ClassConstExpr.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ private static function executeClassConstFetch(
}
}
if (!isset($context->classes[$lcClass])) {
if ('class' === $constName
&& !\in_array(strtolower($className), ['self', 'static', 'parent'], true)) {
// X::class is a pure name literal — Zend resolves it without the
// class existing. Native 8.3+ names (DateException, …) reach here
// on the 8.2 reference profile before/without any declaration (#16828).
$frame->scope[$op->arg1]->string(ltrim($className, '\\'));

return;
}
foreach (self::classNameCandidatesForConstFetch($className, $entry) as $candidate) {
if (self::tryFetchNativePhpClassConstant($candidate, $constNameRaw, $frame->scope[$op->arg1])) {
return;
Expand Down
11 changes: 11 additions & 0 deletions script/emit-helper-runtime-object.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@

$runtime = new Runtime(Runtime::MODE_AOT);
$context = $runtime->loadJitContext();
foreach ($argv as $arg) {
if (str_starts_with($arg, '--preload=')) { // TEMP experiment #16565/#15889
foreach (explode(',', substr($arg, 10)) as $preload) {
$abs = $root.'/'.ltrim($preload, '/');
$block = $runtime->parseAndCompile((string) file_get_contents($abs), basename($abs));
if (null !== $block) {
(new \PHPCompiler\JIT($context))->compile($block);
}
}
}
}
JitVmHelperLink::ensureCompiled($context, $unitPath, $names, 'helper-runtime-emit');

// A stub main drives the same pending-bridge completion a real script
Expand Down
2 changes: 1 addition & 1 deletion test/unit/BootstrapSelfhostBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ public function testCompilerLibSpineSmokeBundleUnitCountAndKeyUnits(): void
$this->assertFileExists($entry);
$contents = (string) file_get_contents($entry);
$count = bootstrap_spine_counts(self::$root)['spine'];
$this->assertSame(4156, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629)');
$this->assertSame(4151, $count, 'M2 spine require_once units track Phase A inventory (#8559, #9234, #11629)');
foreach (self::LIB_SPINE_SMOKE_NEW_UNITS as $unit) {
$this->assertStringContainsString(
"require_once __DIR__.'/../../../{$unit}';",
Expand Down
49 changes: 49 additions & 0 deletions test/unit/ClassConstNameLiteralUndeclaredTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

use PHPUnit\Framework\TestCase;

/**
* X::class is a pure name literal — Zend resolves it without the class being
* declared (zend_compile.c ZEND_FETCH_CLASS_NAME). Native 8.3+ exception names
* (DateException, …) hit this on the 8.2 reference profile (#16828).
*/
final class ClassConstNameLiteralUndeclaredTest extends TestCase
{
public function testUndeclaredClassNameLiteralInConstExpr(): void
{
$code = <<<'PHP'
<?php
class M {
public const MAP = [
'a' => \TotallyUndeclaredClass98::class,
'b' => \DateException::class,
];
}
echo M::MAP['a'], ' ', M::MAP['b'];
PHP;
$this->assertSame('TotallyUndeclaredClass98 DateException', $this->runVm($code));
}

public function testUndeclaredClassNameLiteralAsExpression(): void
{
$code = <<<'PHP'
<?php
echo \SomeNeverDeclaredThing::class;
PHP;
$this->assertSame('SomeNeverDeclaredThing', $this->runVm($code));
}

private function runVm(string $code): string
{
$rt = new Runtime();
$block = $rt->parseAndCompile($code, 'class_const_name_literal_undeclared.php');
ob_start();
$rt->run($block);

return ob_get_clean();
}
}