From 024cb85a165188a2f21842b5e4b620f8eb4e4ab6 Mon Sep 17 00:00:00 2001 From: PurHur Date: Fri, 5 Jun 2026 17:17:30 +0000 Subject: [PATCH] test: add skipped TraitConstructorJitExecuteTest for #4939 Document MCJIT link segfault on TYPE_DECLARE_TRAIT (exit 139) that blocks removing Block::containsTraitConstructorOpcodes until #3609 is fixed. Co-authored-by: Cursor --- test/repro/trait_empty_mcjit_probe.php | 3 + test/unit/TraitConstructorJitExecuteTest.php | 102 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 test/repro/trait_empty_mcjit_probe.php create mode 100644 test/unit/TraitConstructorJitExecuteTest.php diff --git a/test/repro/trait_empty_mcjit_probe.php b/test/repro/trait_empty_mcjit_probe.php new file mode 100644 index 000000000..3b642614f --- /dev/null +++ b/test/repro/trait_empty_mcjit_probe.php @@ -0,0 +1,3 @@ +repoRoot = dirname(__DIR__, 2); + LlvmToolchain::applyCurrentProcessEnv($this->repoRoot); + if (!LlvmToolchain::isReady($this->repoRoot)) { + $reason = LlvmToolchain::readyFailureReason() ?? 'LLVM 9 toolchain not available'; + $this->markTestSkipped($reason.' — trait constructor JIT execute needs LLVM (#4939)'); + } + if (!$this->jitRuntimeProbeGreen()) { + $this->markTestSkipped('jit-runtime-probe failed — MCJIT execute unavailable (#4939)'); + } + if ($this->declareTraitMcjitLinkSegfaults()) { + $this->markTestSkipped( + 'TYPE_DECLARE_TRAIT MCJIT link segfault — remove containsTraitConstructorOpcodes gate after #3609 (#4939)' + ); + } + } + + public function testTraitPromotedConstructorViaMcjit(): void + { + $this->assertMcjitOutput(<<<'PHP' +x, "\n"; +PHP + , + "3\n"); + } + + private function assertMcjitOutput(string $code, string $expected): void + { + $runtime = new Runtime(); + $block = $runtime->parseAndCompile($code, 'trait_ctor_promotion.php'); + $this->assertNotNull($block); + $this->assertTrue(Block::containsTraitConstructorOpcodes($block)); + $this->assertFalse(Block::containsUserClassDeclaredInstancePropertyOpcodes($block)); + $this->assertFalse(Block::requiresVmLowering($block)); + $runtime->jit($block, $code, 'trait_ctor_promotion.php'); + ob_start(); + $runtime->run($block); + $this->assertSame($expected, ob_get_clean()); + } + + private function declareTraitMcjitLinkSegfaults(): bool + { + $probe = $this->repoRoot.'/test/repro/trait_empty_mcjit_probe.php'; + if (!is_file($probe)) { + return true; + } + $cmd = sprintf( + 'bash -lc %s', + escapeshellarg('source '.escapeshellarg($this->repoRoot.'/script/php-env.sh') + .' && '.escapeshellarg(PHP_BINARY).' '.escapeshellarg($this->repoRoot.'/bin/jit.php') + .' -l '.escapeshellarg($probe).' >/dev/null 2>&1') + ); + exec($cmd, $out, $code); + + return 139 === $code; + } + + private function jitRuntimeProbeGreen(): bool + { + $probe = $this->repoRoot.'/script/jit-runtime-probe.php'; + $cmd = sprintf( + 'bash -lc %s', + escapeshellarg('source '.escapeshellarg($this->repoRoot.'/script/php-env.sh') + .' && '.escapeshellarg(PHP_BINARY).' '.escapeshellarg($probe)) + ); + exec($cmd, $out, $code); + + return 0 === $code && str_contains(implode("\n", $out), 'jit-runtime-probe OK'); + } +}