From 78fb5321347a3ad6f2a63603669edd5c224e0a89 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 17 Sep 2026 17:11:13 +0800 Subject: [PATCH] refactor(generator): remove typephp prefix from cache accessors - Renamed typephp_get_method_call_cache to get_method_call_cache - Renamed typephp_get_function_call_cache to get_function_call_cache - Renamed typephp_get_function_resolution_cache to get_function_resolution_cache - Updated all references in compiler base and translator classes - Modified renderDataDeclarations to accept includeGlobals parameter - Added renderGlobalDeclarationsForSource to handle per-source global declarations - Updated extension generation to use new naming convention - Adjusted test assertions to match new function names --- .../src/Build/IncrementalDeclarationTest.php | 41 +++++++++++- .../src/Build/TranslationUnitSplitTest.php | 2 + phpunit/src/CallCacheCodegenTest.php | 8 +-- phpunit/src/DirectGetCalledClassTest.php | 6 +- src/CompilerBase.php | 6 +- src/Translator.php | 63 ++++++++++++++----- 6 files changed, 99 insertions(+), 27 deletions(-) diff --git a/phpunit/src/Build/IncrementalDeclarationTest.php b/phpunit/src/Build/IncrementalDeclarationTest.php index b22d1ae0..837e388a 100644 --- a/phpunit/src/Build/IncrementalDeclarationTest.php +++ b/phpunit/src/Build/IncrementalDeclarationTest.php @@ -65,6 +65,7 @@ PHP); $providerHeader = $compiler->getDeclarationHeaderFile($this->provider); $consumerHeader = $compiler->getDeclarationHeaderFile($this->consumer); $consumerCpp = $this->invoke($compiler, 'getCppFile', $this->consumer); + $providerCpp = $this->invoke($compiler, 'getCppFile', $this->provider); self::assertFileExists($providerHeader); self::assertFileExists($consumerHeader); @@ -84,9 +85,11 @@ PHP); ); self::assertStringContainsString('php_incremental__answer(', $providerDeclarations); self::assertStringContainsString('_const_var_Incremental__LIMIT', $providerDeclarations); - self::assertStringContainsString('_global_var_shared', $providerDeclarations); + self::assertStringNotContainsString('_global_var_shared', $providerDeclarations); + self::assertStringContainsString('extern THREAD_LOCAL php::Var _global_var_shared;', file_get_contents($providerCpp)); self::assertStringNotContainsString('_global_var_shared', $consumerDeclarations); self::assertStringNotContainsString('_global_var_shared', $runtimeDeclarations); + self::assertStringContainsString('extern THREAD_LOCAL php::Var _global_var_shared;', $consumerCode); self::assertStringNotContainsString('php_main(', $providerDeclarations); self::assertStringContainsString('php_main(', $consumerDeclarations); self::assertStringContainsString( @@ -119,6 +122,42 @@ PHP); self::assertSame($this->provider, $symbols['constant:Incremental\\LIMIT']); } + public function testSuperglobalsAreDeclaredInEachUsingSource(): void + { + file_put_contents($this->provider, <<<'PHP' +consumer, "convertProject(); + $runtimeHeader = $this->buildDirectory . '/include/php_incremental_runtime_decl.h'; + $providerCpp = $this->invoke($compiler, 'getCppFile', $this->provider); + $consumerCpp = $this->invoke($compiler, 'getCppFile', $this->consumer); + + $declarations = (string) file_get_contents($providerCpp); + foreach (['_GET', '_POST', '_COOKIE', '_SERVER', '_FILES', '_SESSION', '_REQUEST', '_ENV', 'GLOBALS'] as $name) { + self::assertStringContainsString( + 'extern THREAD_LOCAL php::Var _global_var_' . $name . ';', + $declarations, + ); + } + self::assertStringNotContainsString('_global_var_', (string) file_get_contents($runtimeHeader)); + self::assertStringContainsString( + 'extern THREAD_LOCAL php::Var _global_var__SERVER;', + (string) file_get_contents($consumerCpp), + ); + self::assertStringContainsString( + 'php::Var &_SERVER = _global_var__SERVER;', + (string) file_get_contents($consumerCpp), + ); + } + } + public function testStdContainerParameterContractsSurviveWarmConversionAndInvalidateCallers(): void { file_put_contents($this->provider, <<<'PHP' diff --git a/phpunit/src/Build/TranslationUnitSplitTest.php b/phpunit/src/Build/TranslationUnitSplitTest.php index 5ccc5a4a..b0820e15 100644 --- a/phpunit/src/Build/TranslationUnitSplitTest.php +++ b/phpunit/src/Build/TranslationUnitSplitTest.php @@ -57,6 +57,7 @@ final class TranslationUnitSplitTest extends TestCase $this->set('splitTranslationUnitsEnabled', true); $this->set('generatedMethodBodies', [$body, $small]); $this->set('constData', ['blob' => '1,2,3', 'unused_blob' => '4,5,6']); + $this->set('globalVarsInFile', [$this->source => ['_GET' => 'php::Array']]); $remaining = $this->invoke('splitLargeTranslationUnit', $code, $primary, false); $parts = $this->invoke('getSplitTranslationUnits', $this->source); self::assertCount(1, $parts); @@ -64,6 +65,7 @@ final class TranslationUnitSplitTest extends TestCase self::assertStringContainsString($small, $remaining); $part = file_get_contents($parts[0]); self::assertStringContainsString($body, $part); + self::assertStringContainsString('extern THREAD_LOCAL php::Var _global_var__GET;', $part); self::assertStringContainsString('static const unsigned char blob[]', $part); self::assertStringNotContainsString('unused_blob', $part); self::assertStringNotContainsString('_arginfo.h', $part); diff --git a/phpunit/src/CallCacheCodegenTest.php b/phpunit/src/CallCacheCodegenTest.php index f987fbd0..2668a7bb 100644 --- a/phpunit/src/CallCacheCodegenTest.php +++ b/phpunit/src/CallCacheCodegenTest.php @@ -39,8 +39,8 @@ final class CallCacheCodegenTest extends BaseTest self::assertStringContainsString('php::FunctionCallCacheSlot function_call_cache_map[1]', $extension); self::assertStringContainsString('php::MethodCallCacheSlot method_call_cache_map[2]', $extension); - self::assertStringContainsString('typephp_get_function_call_cache(FunctionCallCacheId cache_id)', $extension); - self::assertStringContainsString('typephp_get_method_call_cache(MethodCallCacheId cache_id)', $extension); + self::assertStringContainsString('get_function_call_cache(FunctionCallCacheId cache_id)', $extension); + self::assertStringContainsString('get_method_call_cache(MethodCallCacheId cache_id)', $extension); } public function testSlotAccessorsDeclareNoexceptWithoutChangingResolvingLookups(): void @@ -61,8 +61,8 @@ final class CallCacheCodegenTest extends BaseTest $extension = file_get_contents($compiler->genExtension()); foreach ([ 'get_property_cache(PropertyCacheId cache_id)', - 'typephp_get_method_call_cache(MethodCallCacheId cache_id)', - 'typephp_get_function_call_cache(FunctionCallCacheId cache_id)', + 'get_method_call_cache(MethodCallCacheId cache_id)', + 'get_function_call_cache(FunctionCallCacheId cache_id)', ] as $signature) { self::assertStringContainsString($signature . ' noexcept;', $header); self::assertStringContainsString($signature . ' noexcept {', $extension); diff --git a/phpunit/src/DirectGetCalledClassTest.php b/phpunit/src/DirectGetCalledClassTest.php index 9601983e..669e02b2 100644 --- a/phpunit/src/DirectGetCalledClassTest.php +++ b/phpunit/src/DirectGetCalledClassTest.php @@ -55,8 +55,8 @@ final class DirectGetCalledClassTest extends BaseTest self::assertStringContainsString('_typephp_called_class', $code); self::assertStringContainsString('CalledClassDynamic\\\\get_called_class', $code); self::assertStringNotContainsString('ZEND_STRL("get_called_class")', $code); - self::assertSame(1, substr_count($code, 'typephp_get_function_resolution_cache(')); - self::assertSame(1, substr_count($code, 'typephp_get_function_call_cache(')); + self::assertSame(1, substr_count($code, 'get_function_resolution_cache(')); + self::assertSame(1, substr_count($code, 'get_function_call_cache(')); self::assertStringContainsString('resolution == 0', $code); self::assertStringContainsString('resolution = php::fn::function_exists(', $code); self::assertStringContainsString(') ? 1 : 2;', $code); @@ -66,7 +66,7 @@ final class DirectGetCalledClassTest extends BaseTest self::assertIsString($extension); self::assertStringContainsString('uint8_t function_resolution_cache_map[1]', $extension); self::assertStringContainsString( - 'uint8_t &typephp_get_function_resolution_cache(FunctionResolutionCacheId cache_id)', + 'uint8_t &get_function_resolution_cache(FunctionResolutionCacheId cache_id)', $extension, ); diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 88441d8e..ddc3f21f 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -1621,7 +1621,7 @@ class CompilerBase implements PropertyAccessContext $this->assertCompilerPhase(self::PHASE_CONVERT, 'method call cache ID allocation'); $id = $this->getStableCallSiteId('method-call'); $this->methodCallCacheIndex = max($this->methodCallCacheIndex, $id + 1); - return 'typephp_get_method_call_cache(MethodCallCacheId{' . $id . '})'; + return 'get_method_call_cache(MethodCallCacheId{' . $id . '})'; } protected function getFunctionCallCache(): string @@ -1629,7 +1629,7 @@ class CompilerBase implements PropertyAccessContext $this->assertCompilerPhase(self::PHASE_CONVERT, 'function call cache ID allocation'); $id = $this->getStableCallSiteId('function-call'); $this->functionCallCacheIndex = max($this->functionCallCacheIndex, $id + 1); - return 'typephp_get_function_call_cache(FunctionCallCacheId{' . $id . '})'; + return 'get_function_call_cache(FunctionCallCacheId{' . $id . '})'; } /** Reserve a request-local namespace-function resolution slot per call site. */ @@ -1638,7 +1638,7 @@ class CompilerBase implements PropertyAccessContext $this->assertCompilerPhase(self::PHASE_CONVERT, 'function resolution cache ID allocation'); $id = $this->getStableCallSiteId('function-resolution'); $this->functionResolutionCacheIndex = max($this->functionResolutionCacheIndex, $id + 1); - return 'typephp_get_function_resolution_cache(FunctionResolutionCacheId{' . $id . '})'; + return 'get_function_resolution_cache(FunctionResolutionCacheId{' . $id . '})'; } protected function getStableCallSiteId(string $domain): int diff --git a/src/Translator.php b/src/Translator.php index fb6a99db..b9c3bb15 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -974,7 +974,11 @@ class Translator extends Preprocessor $this->writeFile($file, $this->renderDataDeclarations()); } - protected function renderDataDeclarations(?string $sourceFile = null, bool $commonOnly = false): string + protected function renderDataDeclarations( + ?string $sourceFile = null, + bool $commonOnly = false, + bool $includeGlobals = true, + ): string { $includeCommon = $sourceFile === null; $projectNamespace = $this->getProjectNamespace(); @@ -986,7 +990,7 @@ class Translator extends Preprocessor // Embedded binaries populate the CLI script fields in $_SERVER at // request startup, even when the source does not reference $_SERVER. - if ($includeCommon + if ($includeGlobals && $includeCommon && !$this->isNanoMode() && $this->isBuildModeBin() && !$this->hasGlobalVar('_SERVER')) { @@ -994,7 +998,7 @@ class Translator extends Preprocessor $this->globalVars['_SERVER'] = Type::ARRAY; } - foreach ($this->globalVars as $name => $type) { + foreach ($includeGlobals ? $this->globalVars : [] as $name => $type) { if ($sourceFile !== null && ($this->globalVarDeclInFile[$name] ?? null) !== $sourceFile) { continue; @@ -1007,7 +1011,7 @@ class Translator extends Preprocessor : Type::VAR; $lines[] = 'extern THREAD_LOCAL ' . $cppType . ' ' . $this->escapeGlobalVar($name) . ';'; } - foreach ($this->nativeStaticInitializers as $name => $_) { + foreach ($includeGlobals ? $this->nativeStaticInitializers : [] as $name => $_) { if ($sourceFile !== null && ($this->nativeStaticInitializerDeclInFile[$name] ?? null) !== $sourceFile) { continue; @@ -1056,9 +1060,9 @@ class Translator extends Preprocessor $lines[] = 'zend_function *get_persistent_method(PersistentFuncId func_id, const php::Str &method_name, PersistentClassId class_id, const php::Str &class_name);'; $lines[] = 'uint32_t get_persistent_prop(PersistentPropertyId prop_id, const php::Str &prop_name, const php::Str &class_name);' . PHP_EOL; $lines[] = 'php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id) noexcept;' . PHP_EOL; - $lines[] = 'php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id) noexcept;' . PHP_EOL; - $lines[] = 'php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id) noexcept;' . PHP_EOL; - $lines[] = 'uint8_t &typephp_get_function_resolution_cache(FunctionResolutionCacheId cache_id) noexcept;' . PHP_EOL; + $lines[] = 'php::MethodCallCacheSlot &get_method_call_cache(MethodCallCacheId cache_id) noexcept;' . PHP_EOL; + $lines[] = 'php::FunctionCallCacheSlot &get_function_call_cache(FunctionCallCacheId cache_id) noexcept;' . PHP_EOL; + $lines[] = 'uint8_t &get_function_resolution_cache(FunctionResolutionCacheId cache_id) noexcept;' . PHP_EOL; } if (!$commonOnly) { @@ -1363,15 +1367,15 @@ php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id) noexcept { return php_request_cache->property_cache_map[static_cast(cache_id)]; } -php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id) noexcept { +php::MethodCallCacheSlot &get_method_call_cache(MethodCallCacheId cache_id) noexcept { return php_request_cache->method_call_cache_map[static_cast(cache_id)]; } -php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id) noexcept { +php::FunctionCallCacheSlot &get_function_call_cache(FunctionCallCacheId cache_id) noexcept { return php_request_cache->function_call_cache_map[static_cast(cache_id)]; } -uint8_t &typephp_get_function_resolution_cache(FunctionResolutionCacheId cache_id) noexcept { +uint8_t &get_function_resolution_cache(FunctionResolutionCacheId cache_id) noexcept { return php_request_cache->function_resolution_cache_map[static_cast(cache_id)]; } CODE; @@ -2848,14 +2852,14 @@ CODE; $runtimeHeader = $this->getIncludeDir() . '/' . $this->getRuntimeDeclarationHeaderName(); $this->writeFile($runtimeHeader, '#pragma once' . PHP_EOL . PHP_EOL - . $this->renderDataDeclarations(null, true) + . $this->renderDataDeclarations(null, true, false) . $this->genNativeObjectForwardDeclarations()); foreach ($this->declarationHeaderFiles as $file => $header) { if (!$this->shouldRegeneratePhpFile($file)) { continue; } $code = $this->renderFunctionDeclarations($file); - $code .= $this->renderDataDeclarations($file); + $code .= $this->renderDataDeclarations($file, false, false); $this->writeFile( $this->getIncludeDir() . '/' . $header, $code, @@ -3054,7 +3058,27 @@ CODE; ...$globalHeaders, ...$declarationHeaders, ...$this->localHeaders, - ]); + ]) . $this->renderGlobalDeclarationsForSource($this->file); + } + + private function renderGlobalDeclarationsForSource(string $sourceFile): string + { + $lines = []; + foreach ($this->globalVarsInFile[$sourceFile] ?? [] as $name => $_) { + $cppType = isset($this->nativeGlobalObjects[$name]) + ? $this->getNativeObjectPointerType($this->nativeGlobalObjects[$name]) + : Type::VAR; + $lines[] = 'extern THREAD_LOCAL ' . $cppType . ' ' . $this->escapeGlobalVar($name) . ';'; + } + foreach ($this->nativeStaticInitializersInFile[$sourceFile] ?? [] as $name => $_) { + $lines[] = 'extern THREAD_LOCAL bool ' . $this->escapeGlobalVar($name) . ';'; + } + if ($lines === []) { + return ''; + } + sort($lines, SORT_STRING); + return PHP_EOL . 'namespace ' . $this->getProjectNamespace() . ' {' . PHP_EOL + . implode(PHP_EOL, $lines) . PHP_EOL . '}' . PHP_EOL; } /** @@ -3062,8 +3086,8 @@ CODE; * does not call every compiled php_* function. Pulling every per-source * declaration into this translation unit made an unrelated declaration * change invalidate the large extension object and greatly increased C++ - * parsing work. Project-wide runtime storage is declared by runtime_decl; - * the generated arginfo headers provide the Zend-facing symbols themselves. + * parsing work. Project sources declare the global storage they use in + * their own translation units; arginfo headers provide Zend-facing symbols. */ private function genExtensionIncludeHeaderFiles(): string { @@ -3573,7 +3597,8 @@ CODE; } $lifecycleSource = $this->getClassArrayConstantLifecycleSourceFile($sourceFile); - $code = $this->renderIncludeHeaderFiles($headers) . PHP_EOL; + $code = $this->renderIncludeHeaderFiles($headers) + . $this->renderGlobalDeclarationsForSource($sourceFile) . PHP_EOL; $code .= 'namespace ' . $this->getProjectNamespace() . ' {' . PHP_EOL . PHP_EOL; $code .= implode('', $sourceDefinitions); $code .= '} // namespace ' . $this->getProjectNamespace() . PHP_EOL; @@ -5966,6 +5991,12 @@ CODE; private function registerServerEnvironment(string $entryFile): string { + if (!$this->hasGlobalVar('_SERVER')) { + $this->addGlobalVar('_SERVER', Type::ARRAY); + } else { + $this->recordGlobalVarUsage('_SERVER'); + } + /** * For long-running (resident) applications, control enters a long-lived * event loop immediately after the current logic finishes. These