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
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ test-docker-exec:
.PHONY: test-docker-quick
test-docker-quick: test-docker-fast

.PHONY: bootstrap-inventory bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-vendor-prelink-bundles bootstrap-vendor-objects bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-runtime-compile-smoke bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-parser-unit-probe bootstrap-selfhost-types-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-helloworld bootstrap-loop-gen1-link bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check
.PHONY: bootstrap-inventory bootstrap-profile bootstrap-aot-lint bootstrap-aot-link bootstrap-aot-link-lib bootstrap-vendor-prelink-bundles bootstrap-vendor-objects bootstrap-selfhost-probe bootstrap-selfhost-link bootstrap-selfhost-compile-smoke bootstrap-selfhost-runtime-compile-smoke bootstrap-m3-emit-tu-execute bootstrap-selfhost-compiler-driver-smoke bootstrap-selfhost-jit-unit-probe bootstrap-selfhost-vm-unit-probe bootstrap-selfhost-parser-unit-probe bootstrap-selfhost-types-unit-probe bootstrap-selfhost-lib-spine-smoke bootstrap-selfhost-lib-spine-vm-smoke bootstrap-selfhost-helloworld bootstrap-loop-gen1-link bootstrap-loop-probe bootstrap-loop-probe-dry bootstrap-loop-probe-dry-run bootstrap-wave-check
bootstrap-inventory:
php script/bootstrap-inventory.php
bootstrap-profile: bootstrap-inventory
Expand All @@ -271,6 +271,8 @@ bootstrap-selfhost-compile-smoke-run:
./script/bootstrap-selfhost-compile-smoke-run.sh
bootstrap-selfhost-runtime-compile-smoke:
./script/bootstrap-selfhost-runtime-compile-smoke.sh
bootstrap-m3-emit-tu-execute:
./script/bootstrap-m3-emit-tu-execute.sh
bootstrap-selfhost-compiler-driver-smoke:
./script/bootstrap-selfhost-compiler-driver-smoke-link.sh
bootstrap-selfhost-jit-unit-probe:
Expand Down
232 changes: 182 additions & 50 deletions lib/JIT.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public function compile(Block $block): PHPLLVM\Value {
}
$return = $this->compileBlock($block);
$this->runQueue();
$this->finalizeM3EmitTuRuntimeSpineAfterQueue();

return $return;
}
Expand Down Expand Up @@ -1661,50 +1662,11 @@ private function compileM3EmitTuRuntimeSpineDecls(): void
}
$stubBlock = $this->m3EmitTuMainBlock;
if ($this->shouldUseM3CompileDriverRealLowering()) {
$runtimeMethods = [
'parse' => true,
'compileemitsmoke' => true,
'standalone' => true,
];
foreach ($this->m3EmitTuMainBlock->opCodes as $op) {
if (OpCode::TYPE_DECLARE_CLASS !== $op->type) {
continue;
}
$nameOp = $this->m3EmitTuMainBlock->getOperand($op->arg1);
if (!$nameOp instanceof Operand\Literal) {
continue;
}
$lc = strtolower(str_replace('/', '\\', ltrim($nameOp->value, '\\')));
if ('phpcompiler\\runtime' !== $lc || null === $op->block1) {
continue;
}
$this->context->pushScope();
$this->context->scope->classId = $this->context->type->object->declareClass($nameOp);
$this->context->scope->className = $lc;
foreach ($op->block1->opCodes as $methodOp) {
if (OpCode::TYPE_DECLARE_METHOD !== $methodOp->type) {
continue;
}
$methodOpName = $op->block1->getOperand($methodOp->arg1);
if (!$methodOpName instanceof Operand\Literal) {
continue;
}
$methodLc = strtolower($methodOpName->value);
if (!isset($runtimeMethods[$methodLc])) {
continue;
}
$logical = $lc.'::'.$methodLc;
if (!isset($this->context->functions[strtolower($logical)])) {
$this->compileBlock($methodOp->block1, $logical);
}
}
$this->context->popScope();
$this->compileM3EmitTuRuntimeSpineMethodsForRealLowering();
foreach (['initparsepipeline', 'initcompiler', 'initvmcontext', 'loadcoremodules'] as $methodLc) {
$this->compileM3EmitTuRuntimeMethodFromQueue($methodLc);
}
$this->emitM3EmitTuRuntimeConstructNativeFunction(
$this->llvmInternalName('PHPCompiler\\Runtime::__construct'),
'PHPCompiler\\Runtime::__construct',
$stubBlock
);
$this->runQueue();
$this->compileM3EmitTuRuntimeParseAndCompileNativeDecl([
'parseandcompile' => true,
'parseandcompileemitsmoke' => true,
Expand All @@ -1720,11 +1682,6 @@ private function compileM3EmitTuRuntimeSpineDecls(): void
'PHPCompiler\\Runtime::compileEmitSmoke',
$stubBlock
);
$this->emitM3EmitTuRuntimeStandaloneStubNative(
$this->llvmInternalName('PHPCompiler\\Runtime::standalone'),
'PHPCompiler\\Runtime::standalone',
$stubBlock
);
$this->emitM3EmitTuRuntimeConstructNativeFunction(
$this->llvmInternalName('PHPCompiler\\Runtime::__construct'),
'PHPCompiler\\Runtime::__construct',
Expand All @@ -1740,8 +1697,33 @@ private function compileM3EmitTuRuntimeSpineDecls(): void
$stubBlock
);
}
$this->emitM3EmitTuRuntimeStandaloneStubNative(
$this->llvmInternalName('PHPCompiler\\Runtime::standalone'),
'PHPCompiler\\Runtime::standalone',
$stubBlock
);
$this->compileM3EmitTuCompilerEmitSmokeNativeDecl();
if (!$this->shouldUseM3CompileDriverRealLowering()) {
$this->runQueue();
}
}

/**
* After spine pre-lower, register emit-bridge decls that call real Runtime::parse (#2512, #2550).
*/
private function finalizeM3EmitTuRuntimeSpineAfterQueue(): void
{
if (!$this->shouldUseM3EmitTuNativeBridge()
|| !$this->shouldUseM3CompileDriverRealLowering()
|| null === $this->m3EmitTuMainBlock
) {
return;
}
$this->compileM3EmitTuRuntimeParseAndCompileNativeDecl([
'parseandcompile' => true,
'parseandcompileemitsmoke' => true,
]);
$this->compileM3EmitTuCompilerEmitSmokeNativeDecl();
$this->runQueue();
}

/**
Expand All @@ -1758,7 +1740,7 @@ private function compileM3EmitTuRuntimeParseAndCompileNativeDecl(array $methods)
$this->context->scope->classId = $this->context->type->object->lookup('PHPCompiler\\Runtime');
$this->context->scope->className = 'phpcompiler\\runtime';
foreach (array_keys($methods) as $methodLc) {
$logical = 'PHPCompiler\\Runtime::'.$methodLc;
$logical = 'phpcompiler\\runtime::'.$methodLc;
$lc = strtolower($logical);
if (isset($this->context->functions[$lc])) {
continue;
Expand Down Expand Up @@ -2083,6 +2065,156 @@ private function compileM3EmitTuRuntimeMethodFromQueue(string $methodLc): void

return;
}
$this->compileM3EmitTuRuntimeMethodFromDeclareClassBlocks([$methodLc]);
$this->compileM3EmitTuRuntimeMethodFromModules($methodLc);
}

/** Pre-lower Runtime spine callees before native emit {main} bridge (#2550). */
private function compileM3EmitTuRuntimeSpineMethodsForRealLowering(): void
{
if (!$this->shouldUseM3EmitTuNativeBridge() || !$this->shouldUseM3CompileDriverRealLowering()) {
return;
}
foreach (['__construct', 'parse', 'compileemitsmoke'] as $methodLc) {
$this->compileM3EmitTuRuntimeMethodFromModules($methodLc);
}
$this->runQueue();
}

private function compileM3EmitTuRuntimeMethodFromModules(string $methodLc): void
{
$logical = 'PHPCompiler\\Runtime::'.$methodLc;
$lc = strtolower($logical);
if (isset($this->context->functions[$lc])) {
return;
}
foreach ($this->context->runtime->modules as $module) {
foreach ($module->getFunctions() as $func) {
if (!$func instanceof CoreFunc\PHP) {
continue;
}
if (strtolower($func->getName()) !== $lc) {
continue;
}
$this->compileBlock($func->block, $logical);

return;
}
}
if (null === $this->m3EmitTuMainBlock) {
return;
}
foreach ($this->m3EmitTuMainBlock->opCodes as $op) {
if (OpCode::TYPE_DECLARE_CLASS !== $op->type) {
continue;
}
$nameOp = $this->m3EmitTuMainBlock->getOperand($op->arg1);
if (!$nameOp instanceof Operand\Literal) {
continue;
}
$classLc = strtolower(str_replace('/', '\\', ltrim($nameOp->value, '\\')));
if ('phpcompiler\\runtime' !== $classLc || null === $op->block1) {
continue;
}
$this->context->pushScope();
$this->context->scope->classId = $this->context->type->object->lookup('PHPCompiler\\Runtime');
$this->context->scope->className = $classLc;
foreach ($op->block1->opCodes as $methodOp) {
if (OpCode::TYPE_DECLARE_METHOD !== $methodOp->type) {
continue;
}
$methodOpName = $op->block1->getOperand($methodOp->arg1);
if (!$methodOpName instanceof Operand\Literal || strtolower($methodOpName->value) !== $methodLc) {
continue;
}
if (null !== $methodOp->block1) {
$this->compileBlock($methodOp->block1, $logical);
}
}
$this->context->popScope();

return;
}
$runtimePath = dirname(__DIR__).'/Runtime.php';
if (!is_file($runtimePath)) {
return;
}
try {
$script = $this->context->runtime->parse((string) file_get_contents($runtimePath), $runtimePath);
} catch (\Throwable $e) {
return;
}
foreach ($script->functions as $cfgFunc) {
$funcLc = strtolower($cfgFunc->name);
if ($funcLc !== $lc && !str_ends_with($funcLc, '\\'.$methodLc)) {
continue;
}
$compiled = $this->context->runtime->compileFunc($logical, $cfgFunc);
if ($compiled instanceof CoreFunc\PHP) {
$this->compileBlock($compiled->block, $logical);
}

return;
}
}

/**
* Find Runtime methods on bundled declare_class blocks (private init* may be absent from queue).
*
* @param list<string> $methodLcs lowercase method names without class prefix
*/
private function compileM3EmitTuRuntimeMethodFromDeclareClassBlocks(array $methodLcs): void
{
if (!$this->shouldUseM3EmitTuNativeBridge()) {
return;
}
$allowed = array_fill_keys($methodLcs, true);
$blocks = [];
if (null !== $this->m3EmitTuMainBlock) {
$blocks[] = $this->m3EmitTuMainBlock;
}
foreach ($this->queue as $item) {
$blocks[] = $item[1];
}
foreach ($blocks as $block) {
if (null === $block) {
continue;
}
foreach ($block->opCodes as $op) {
if (OpCode::TYPE_DECLARE_CLASS !== $op->type) {
continue;
}
$nameOp = $block->getOperand($op->arg1);
if (!$nameOp instanceof Operand\Literal) {
continue;
}
$classLc = strtolower(str_replace('/', '\\', ltrim($nameOp->value, '\\')));
if ('phpcompiler\\runtime' !== $classLc || null === $op->block1) {
continue;
}
$this->context->pushScope();
$this->context->scope->classId = $this->context->type->object->declareClass($nameOp);
$this->context->scope->className = $classLc;
foreach ($op->block1->opCodes as $methodOp) {
if (OpCode::TYPE_DECLARE_METHOD !== $methodOp->type) {
continue;
}
$methodOpName = $op->block1->getOperand($methodOp->arg1);
if (!$methodOpName instanceof Operand\Literal) {
continue;
}
$methodLc = strtolower($methodOpName->value);
if (!isset($allowed[$methodLc])) {
continue;
}
$logical = $classLc.'::'.$methodLc;
if (!isset($this->context->functions[strtolower($logical)])) {
$this->compileBlock($methodOp->block1, $logical);
}
}
$this->context->popScope();
}
}
}

/** Pre-lower Compiler::compile only; callees compile on demand (#1937). */
Expand Down
37 changes: 30 additions & 7 deletions lib/JIT/BootstrapCompileSmokeM3Emit.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace PHPCompiler\JIT;

require_once __DIR__.'/RuntimeEmitTuAlloc.php';
require_once __DIR__.'/RuntimeEmitTuInit.php';

use PHPLLVM\Builder;
use PHPLLVM\Value;
Expand Down Expand Up @@ -106,13 +107,17 @@ public static function emit(Context $context, Value $sourceFile, Value $outFile,
$context->builder->returnValue($retFail);

$context->builder->positionAtEnd($readOk);
// Minimal Runtime shell — full Object_::allocate() LLVM 9 link crash (#2540).
$runtime = RuntimeEmitTuAlloc::emit($context);
$context->builder->call(
self::runtimeSpine($context, '__construct', 'void', ['__object__*', 'int64']),
$runtime,
$i64->constInt(self::MODE_AOT, false)
);
$mode = $i64->constInt(self::MODE_AOT, false);
if (self::shouldUseEmitTuRealLowering($context)) {
RuntimeEmitTuInit::emitInitSequence($context, $runtime, $mode);
} else {
$context->builder->call(
self::runtimeSpine($context, '__construct', 'void', ['__object__*', 'int64']),
$runtime,
$mode
);
}
$parseAndCompileMethod = str_starts_with($logPrefix, 'runtime_compile_smoke_m3_emit')
? 'parseandcompile'
: 'parseandcompileemitsmoke';
Expand Down Expand Up @@ -157,6 +162,14 @@ public static function emit(Context $context, Value $sourceFile, Value $outFile,
$context->builder->returnValue($retOk);
}

private static function shouldUseEmitTuRealLowering(Context $context): bool
{
$flag = getenv('PHP_COMPILER_M3_COMPILE_DRIVER');

return ('1' === $flag || 'true' === strtolower((string) $flag))
&& ('1' === getenv('PHP_COMPILER_M3_EMIT_TU') || 'true' === strtolower((string) getenv('PHP_COMPILER_M3_EMIT_TU')));
}

private static function echoPhaseError(Context $context, string $logPrefix, string $line1, string $phase): void
{
ValueEchoHelper::echoLiteral($context, $line1."\n");
Expand Down Expand Up @@ -268,13 +281,23 @@ private static function compilerSpine(
);
}

/** @param list<string> $paramTypeNames */
public static function runtimeSpineFn(
Context $context,
string $methodLc,
string $returnTypeName,
array $paramTypeNames
): Value {
return self::runtimeSpine($context, $methodLc, $returnTypeName, $paramTypeNames);
}

private static function runtimeSpine(
Context $context,
string $methodLc,
string $returnTypeName,
array $paramTypeNames
): Value {
$logical = 'PHPCompiler\\Runtime::'.$methodLc;
$logical = 'phpcompiler\\runtime::'.$methodLc;
$lc = strtolower($logical);
if (isset($context->functions[$lc])) {
return $context->functions[$lc];
Expand Down
4 changes: 3 additions & 1 deletion lib/JIT/Builtin/Type/Object_.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public function allocate(int $classId): PHPLLVM\Value
}

/**
* Object shell for M3 emit-helper TU — property slots only, no defaults/ht init (#2540).
* Object shell for M3 emit-helper TU — slots + defaults/ht, no vendor ctor (#2540, #2550).
*/
public function allocateEmitTuShell(int $classId): PHPLLVM\Value
{
Expand Down Expand Up @@ -306,6 +306,8 @@ public function allocateEmitTuShell(int $classId): PHPLLVM\Value

if ($propCount > 0) {
$this->initPropertySlots($obj, $propCount);
$this->initPropertyDefaults($obj, $classId);
$this->initEmptyHashtableProperties($obj, $classId);
}

return $obj;
Expand Down
2 changes: 1 addition & 1 deletion lib/JIT/RuntimeEmitTuAlloc.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* Allocate Runtime shell in M3 emit-helper TU without PHP CFG `new Runtime` (#2540, #2442).
*
* Caller must run initParsePipeline / initCompiler / initVmContext / loadCoreModules (#2550).
* Caller must run RuntimeEmitTuInit::emitInitSequence after alloc (#2550).
*/
final class RuntimeEmitTuAlloc
{
Expand Down
Loading