From 8f32497de76452491a56985e2f76c3018c68b9dc Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 25 Aug 2026 20:51:14 +0800 Subject: [PATCH] refactor(compiler): strongly type symbol cache IDs --- phpunit/src/CompilerBaseApiTest.php | 11 +++-- src/CompilerBase.php | 21 ++++++--- src/Translator.php | 67 +++++++++++++++++------------ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/phpunit/src/CompilerBaseApiTest.php b/phpunit/src/CompilerBaseApiTest.php index 29c56ccc..706b4ec5 100644 --- a/phpunit/src/CompilerBaseApiTest.php +++ b/phpunit/src/CompilerBaseApiTest.php @@ -89,8 +89,8 @@ class CompilerBaseApiTest extends TestCase $methodPtr = $this->invokeMethod('getMethodPtr', 'LateKnownClass', 'run'); - $this->assertStringStartsWith('get_method(0, ', $methodPtr); - $this->assertStringContainsString(', 0, ', $methodPtr); + $this->assertStringStartsWith('get_method(RequestFuncId{0}, ', $methodPtr); + $this->assertStringContainsString(', RequestClassId{0}, ', $methodPtr); $this->assertSame( ['LateKnownClass::run' => 0], $this->getPropertyValue('funcMap'), @@ -1258,8 +1258,13 @@ YAML); 'static php::PersistentCacheSlot php_persistent_property_map', $extension, ); + $this->assertStringContainsString('enum class RequestClassId : uint32_t {};', $data); + $this->assertStringContainsString('enum class PersistentClassId : uint32_t {};', $data); + $this->assertStringContainsString('enum class RequestFuncId : uint32_t {};', $data); + $this->assertStringContainsString('enum class PersistentFuncId : uint32_t {};', $data); + $this->assertStringContainsString('enum class PersistentPropertyId : uint32_t {};', $data); $this->assertStringContainsString('get_persistent_class', $extension); - $this->assertStringContainsString('php::getPersistentCache(php_persistent_class_map[class_id]', $extension); + $this->assertStringContainsString('php::getPersistentCache(php_persistent_class_map[index]', $extension); $this->assertStringContainsString('for (auto &slot : php_persistent_class_map)', $extension); $this->assertStringContainsString('php::resetPersistentCache(slot);', $extension); $this->assertStringNotContainsString('#ifdef ZTS', $data); diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 92756a84..0924868b 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -1358,8 +1358,10 @@ class CompilerBase implements PropertyAccessContext protected function getClassEntryPtr(string $className): string { $id = $this->getClassId($className); - $helper = isset($this->persistentClassMap[$className]) ? 'get_persistent_class' : 'get_class'; - return $helper . '(' . $id . ', ' . $this->getLiteralString($className) . ')'; + $persistent = isset($this->persistentClassMap[$className]); + $helper = $persistent ? 'get_persistent_class' : 'get_class'; + $idType = $persistent ? 'PersistentClassId' : 'RequestClassId'; + return $helper . '(' . $idType . '{' . $id . '}, ' . $this->getLiteralString($className) . ')'; } /** @@ -1420,8 +1422,10 @@ class CompilerBase implements PropertyAccessContext throw new \LogicException('Class methods must be resolved through getMethodPtr()'); } $id = $this->getFuncId($funcName); - $helper = isset($this->persistentFuncMap[$funcName]) ? 'get_persistent_func' : 'get_func'; - return $helper . '(' . $id . ', ' . $this->getLiteralString($funcName) . ')'; + $persistent = isset($this->persistentFuncMap[$funcName]); + $helper = $persistent ? 'get_persistent_func' : 'get_func'; + $idType = $persistent ? 'PersistentFuncId' : 'RequestFuncId'; + return $helper . '(' . $idType . '{' . $id . '}, ' . $this->getLiteralString($funcName) . ')'; } protected function getMethodPtr(string $class, string $method): string @@ -1442,14 +1446,17 @@ class CompilerBase implements PropertyAccessContext )); } $helper = $persistentMethod ? 'get_persistent_method' : 'get_method'; - return $helper . '(' . $funcId . ', ' . $this->getLiteralString($method) . ', ' . $classId . ', ' . $this->getLiteralString($class) . ')'; + $funcIdType = $persistentMethod ? 'PersistentFuncId' : 'RequestFuncId'; + $classIdType = $persistentClass ? 'PersistentClassId' : 'RequestClassId'; + return $helper . '(' . $funcIdType . '{' . $funcId . '}, ' . $this->getLiteralString($method) + . ', ' . $classIdType . '{' . $classId . '}, ' . $this->getLiteralString($class) . ')'; } protected function getPropertyOffset(string $class, string $prop): string { $propId = $this->getPropertyId($class, $prop); - $classId = $this->getClassId($class); - return 'get_persistent_prop(' . $propId . ', ' . $this->getLiteralString($prop) . ', ' . $classId . ', ' . $this->getLiteralString($class) . ')'; + return 'get_persistent_prop(PersistentPropertyId{' . $propId . '}, ' + . $this->getLiteralString($prop) . ', ' . $this->getLiteralString($class) . ')'; } protected function writeLog($msg): void diff --git a/src/Translator.php b/src/Translator.php index ea5b3a73..dcfe3a19 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -777,13 +777,19 @@ class Translator extends Preprocessor $lines[] = $pythonModuleDeclarations; } - $lines[] = 'zend_class_entry *get_class(int class_id, const php::Str &class_name);'; - $lines[] = 'zend_function *get_func(int func_id, const php::Str &func_name);'; - $lines[] = 'zend_function *get_method(int func_id, const php::Str &method_name, int class_id, const php::Str &class_name);'; - $lines[] = 'zend_class_entry *get_persistent_class(int class_id, const php::Str &class_name);'; - $lines[] = 'zend_function *get_persistent_func(int func_id, const php::Str &func_name);'; - $lines[] = 'zend_function *get_persistent_method(int func_id, const php::Str &method_name, int class_id, const php::Str &class_name);'; - $lines[] = 'uint32_t get_persistent_prop(int prop_id, const php::Str &prop_name, int class_id, const php::Str &class_name);' . PHP_EOL; + $lines[] = 'enum class RequestClassId : uint32_t {};'; + $lines[] = 'enum class PersistentClassId : uint32_t {};'; + $lines[] = 'enum class RequestFuncId : uint32_t {};'; + $lines[] = 'enum class PersistentFuncId : uint32_t {};'; + $lines[] = 'enum class PersistentPropertyId : uint32_t {};' . PHP_EOL; + + $lines[] = 'zend_class_entry *get_class(RequestClassId class_id, const php::Str &class_name);'; + $lines[] = 'zend_function *get_func(RequestFuncId func_id, const php::Str &func_name);'; + $lines[] = 'zend_function *get_method(RequestFuncId func_id, const php::Str &method_name, RequestClassId class_id, const php::Str &class_name);'; + $lines[] = 'zend_class_entry *get_persistent_class(PersistentClassId class_id, const php::Str &class_name);'; + $lines[] = 'zend_function *get_persistent_func(PersistentFuncId func_id, const php::Str &func_name);'; + $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; foreach ($this->getClassLikesWithConstants() as $classDef) { foreach ($classDef->constants as $constant) { @@ -876,49 +882,56 @@ class Translator extends Preprocessor $code .= "// functions \n"; $code .= <<<'CODE' -zend_class_entry *get_class(int class_id, const php::Str &class_name) { - if (UNEXPECTED(php_class_map[class_id] == nullptr)) { - php_class_map[class_id] = php::getClassEntrySafe(class_name); +zend_class_entry *get_class(RequestClassId class_id, const php::Str &class_name) { + const auto index = static_cast(class_id); + if (UNEXPECTED(php_class_map[index] == nullptr)) { + php_class_map[index] = php::getClassEntrySafe(class_name); } - return php_class_map[class_id]; + return php_class_map[index]; } -zend_function *get_func(int func_id, const php::Str &func_name) { - if (UNEXPECTED(php_func_map[func_id] == nullptr)) { - php_func_map[func_id] = php::getFunction(func_name); +zend_function *get_func(RequestFuncId func_id, const php::Str &func_name) { + const auto index = static_cast(func_id); + if (UNEXPECTED(php_func_map[index] == nullptr)) { + php_func_map[index] = php::getFunction(func_name); } - return php_func_map[func_id]; + return php_func_map[index]; } -zend_function *get_method(int func_id, const php::Str &method_name, int class_id, const php::Str &class_name) { - if (UNEXPECTED(php_func_map[func_id] == nullptr)) { +zend_function *get_method(RequestFuncId func_id, const php::Str &method_name, RequestClassId class_id, const php::Str &class_name) { + const auto index = static_cast(func_id); + if (UNEXPECTED(php_func_map[index] == nullptr)) { auto ce = get_class(class_id, class_name); - php_func_map[func_id] = php::getMethod(ce, method_name); + php_func_map[index] = php::getMethod(ce, method_name); } - return php_func_map[func_id]; + return php_func_map[index]; } -zend_class_entry *get_persistent_class(int class_id, const php::Str &class_name) { - return php::getPersistentCache(php_persistent_class_map[class_id], [&]() { +zend_class_entry *get_persistent_class(PersistentClassId class_id, const php::Str &class_name) { + const auto index = static_cast(class_id); + return php::getPersistentCache(php_persistent_class_map[index], [&]() { return php::getClassEntrySafe(class_name); }); } -zend_function *get_persistent_func(int func_id, const php::Str &func_name) { - return php::getPersistentCache(php_persistent_func_map[func_id], [&]() { +zend_function *get_persistent_func(PersistentFuncId func_id, const php::Str &func_name) { + const auto index = static_cast(func_id); + return php::getPersistentCache(php_persistent_func_map[index], [&]() { return php::getFunction(func_name); }); } -zend_function *get_persistent_method(int func_id, const php::Str &method_name, int class_id, const php::Str &class_name) { - return php::getPersistentCache(php_persistent_func_map[func_id], [&]() { +zend_function *get_persistent_method(PersistentFuncId func_id, const php::Str &method_name, PersistentClassId class_id, const php::Str &class_name) { + const auto index = static_cast(func_id); + return php::getPersistentCache(php_persistent_func_map[index], [&]() { auto ce = get_persistent_class(class_id, class_name); return php::getMethod(ce, method_name); }); } -uint32_t get_persistent_prop(int prop_id, const php::Str &prop_name, int class_id, const php::Str &class_name) { - auto value = php::getPersistentCache(php_persistent_property_map[prop_id], [&]() { +uint32_t get_persistent_prop(PersistentPropertyId prop_id, const php::Str &prop_name, const php::Str &class_name) { + const auto index = static_cast(prop_id); + auto value = php::getPersistentCache(php_persistent_property_map[index], [&]() { return php::getPropertyOffset(class_name, prop_name) + 1024; }); return value - 1024;