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
master
韩天峰 3 weeks ago
parent f127dadf5d
commit 78fb532134
  1. 41
      phpunit/src/Build/IncrementalDeclarationTest.php
  2. 2
      phpunit/src/Build/TranslationUnitSplitTest.php
  3. 8
      phpunit/src/CallCacheCodegenTest.php
  4. 6
      phpunit/src/DirectGetCalledClassTest.php
  5. 6
      src/CompilerBase.php
  6. 63
      src/Translator.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'
<?php
function readGlobals(): array
{
return [$_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_SESSION, $_REQUEST, $_ENV, $GLOBALS];
}
PHP);
file_put_contents($this->consumer, "<?php\nfunction main(): void {}\n");
foreach ([1, 2] as $_) {
$compiler = $this->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'

@ -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);

@ -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);

@ -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,
);

@ -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

@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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

Loading…
Cancel
Save