diff options
-rw-r--r-- | Zend/zend_API.c | 36 | ||||
-rw-r--r-- | Zend/zend_execute.c | 35 | ||||
-rwxr-xr-x | build/gen_stub.php | 60 | ||||
-rw-r--r-- | ext/ffi/ffi.stub.php | 14 | ||||
-rw-r--r-- | ext/ffi/ffi_arginfo.h | 4 |
5 files changed, 96 insertions, 53 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 58b743e641..11760d50f0 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2455,10 +2455,40 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend for (i = 0; i < num_args; i++) { if (ZEND_TYPE_HAS_CLASS(new_arg_info[i].type)) { ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type) - && "Only simple classes are currently supported"); + && "Should be stored as simple name"); const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, - zend_string_init_interned(class_name, strlen(class_name), 1)); + + size_t num_types = 1; + const char *p = class_name; + while ((p = strchr(p, '|'))) { + num_types++; + p++; + } + + if (num_types == 1) { + /* Simple class type */ + ZEND_TYPE_SET_PTR(new_arg_info[i].type, + zend_string_init_interned(class_name, strlen(class_name), 1)); + } else { + /* Union type */ + zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types)); + list->num_types = num_types; + ZEND_TYPE_SET_LIST(new_arg_info[i].type, list); + + const char *start = class_name; + uint32_t j = 0; + while (true) { + const char *end = strchr(start, '|'); + zend_string *str = + zend_string_init(start, end ? end - start : strlen(start), 1); + list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0); + if (!end) { + break; + } + start = end + 1; + j++; + } + } } } } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 16eafc39ba..14ebcec1b7 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -951,6 +951,13 @@ ZEND_API zend_bool zend_value_instanceof_static(zval *zv) { return instanceof_function(Z_OBJCE_P(zv), called_scope); } +/* The cache_slot may only be NULL in debug builds, where arginfo verification of + * internal functions is enabled. Avoid unnecessary checks in release builds. */ +#if ZEND_DEBUG +# define HAVE_CACHE_SLOT (cache_slot != NULL) +#else +# define HAVE_CACHE_SLOT 1 +#endif static zend_always_inline zend_bool zend_check_type_slow( zend_type type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope, @@ -962,31 +969,39 @@ static zend_always_inline zend_bool zend_check_type_slow( if (ZEND_TYPE_HAS_LIST(type)) { zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { - if (*cache_slot) { + if (HAVE_CACHE_SLOT && *cache_slot) { ce = *cache_slot; } else { ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (!ce) { - cache_slot++; + if (HAVE_CACHE_SLOT) { + cache_slot++; + } continue; } - *cache_slot = ce; + if (HAVE_CACHE_SLOT) { + *cache_slot = ce; + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; } - cache_slot++; + if (HAVE_CACHE_SLOT) { + cache_slot++; + } } ZEND_TYPE_LIST_FOREACH_END(); } else { - if (EXPECTED(*cache_slot)) { + if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) { ce = (zend_class_entry *) *cache_slot; } else { ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (UNEXPECTED(!ce)) { goto builtin_types; } - *cache_slot = (void *) ce; + if (HAVE_CACHE_SLOT) { + *cache_slot = (void *) ce; + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1079,8 +1094,6 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ for (i = 0; i < num_args; ++i) { zend_arg_info *cur_arg_info; - void *dummy_cache_slot = NULL; - if (EXPECTED(i < fbc->common.num_args)) { cur_arg_info = &fbc->common.arg_info[i]; } else if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) { @@ -1090,7 +1103,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ } if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &dummy_cache_slot, fbc->common.scope, 0, /* is_internal */ 1))) { + && UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) { return 0; } arg++; @@ -1215,8 +1228,6 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con static bool zend_verify_internal_return_type(zend_function *zf, zval *ret) { zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; - void *dummy_cache_slot = NULL; - if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) { if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) { zend_verify_void_return_error(zf, zend_zval_type_name(ret), ""); @@ -1225,7 +1236,7 @@ static bool zend_verify_internal_return_type(zend_function *zf, zval *ret) return 1; } - if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &dummy_cache_slot, NULL, 1, /* is_internal */ 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) { zend_verify_internal_return_error(zf, ret); return 0; } diff --git a/build/gen_stub.php b/build/gen_stub.php index 5d651daaf2..6d1ae99ebc 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -293,20 +293,17 @@ class Type { return null; } - public function tryToRepresentableType(): ?RepresentableType { - $classType = null; + public function toArginfoType(): ?ArginfoType { + $classTypes = []; $builtinTypes = []; foreach ($this->types as $type) { if ($type->isBuiltin) { $builtinTypes[] = $type; - } else if ($classType === null) { - $classType = $type; } else { - // We can only represent a single class type. - return null; + $classTypes[] = $type; } } - return new RepresentableType($classType, $builtinTypes); + return new ArginfoType($classTypes, $builtinTypes); } public static function equals(?Type $a, ?Type $b): bool { @@ -339,18 +336,32 @@ class Type { } } -class RepresentableType { - /** @var ?SimpleType $classType */ - public $classType; +class ArginfoType { + /** @var ClassType[] $classTypes */ + public $classTypes; + /** @var SimpleType[] $builtinTypes */ - public $builtinTypes; + private $builtinTypes; - public function __construct(?SimpleType $classType, array $builtinTypes) { - $this->classType = $classType; + public function __construct(array $classTypes, array $builtinTypes) { + $this->classTypes = $classTypes; $this->builtinTypes = $builtinTypes; } + public function hasClassType(): bool { + return !empty($this->classTypes); + } + + public function toClassTypeString(): string { + return implode('|', array_map(function(SimpleType $type) { + return $type->toEscapedName(); + }, $this->classTypes)); + } + public function toTypeMask(): string { + if (empty($this->builtinTypes)) { + return '0'; + } return implode('|', array_map(function(SimpleType $type) { return $type->toTypeMask(); }, $this->builtinTypes)); @@ -1362,24 +1373,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string { $simpleReturnType->toEscapedName(), $returnType->isNullable() ); } - } else if (null !== $representableType = $returnType->tryToRepresentableType()) { - if ($representableType->classType !== null) { + } else { + $arginfoType = $returnType->toArginfoType(); + if ($arginfoType->hasClassType()) { $code .= sprintf( "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(%s, %d, %d, %s, %s)\n", $funcInfo->getArgInfoName(), $funcInfo->return->byRef, $funcInfo->numRequiredArgs, - $representableType->classType->toEscapedName(), $representableType->toTypeMask() + $arginfoType->toClassTypeString(), $arginfoType->toTypeMask() ); } else { $code .= sprintf( "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(%s, %d, %d, %s)\n", $funcInfo->getArgInfoName(), $funcInfo->return->byRef, $funcInfo->numRequiredArgs, - $representableType->toTypeMask() + $arginfoType->toTypeMask() ); } - } else { - throw new Exception('Unimplemented'); } } else { $code .= sprintf( @@ -1409,25 +1419,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string { $argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : "" ); } - } else if (null !== $representableType = $argType->tryToRepresentableType()) { - if ($representableType->classType !== null) { + } else { + $arginfoType = $argType->toArginfoType(); + if ($arginfoType->hasClassType()) { $code .= sprintf( "\tZEND_%s_OBJ_TYPE_MASK(%s, %s, %s, %s, %s)\n", $argKind, $argInfo->getSendByString(), $argInfo->name, - $representableType->classType->toEscapedName(), - $representableType->toTypeMask(), + $arginfoType->toClassTypeString(), $arginfoType->toTypeMask(), $argInfo->getDefaultValueAsArginfoString() ); } else { $code .= sprintf( "\tZEND_%s_TYPE_MASK(%s, %s, %s, %s)\n", $argKind, $argInfo->getSendByString(), $argInfo->name, - $representableType->toTypeMask(), + $arginfoType->toTypeMask(), $argInfo->getDefaultValueAsArginfoString() ); } - } else { - throw new Exception('Unimplemented'); } } else { $code .= sprintf( diff --git a/ext/ffi/ffi.stub.php b/ext/ffi/ffi.stub.php index 4b345b9147..dba2dcc308 100644 --- a/ext/ffi/ffi.stub.php +++ b/ext/ffi/ffi.stub.php @@ -33,17 +33,11 @@ final class FFI /** @prefer-ref $ptr */ public static function addr(FFI\CData $ptr): FFI\CData {} - /** - * @param FFI\CData|FFI\CType $ptr - * @prefer-ref $ptr - */ - public static function sizeof($ptr): int {} + /** @prefer-ref $ptr */ + public static function sizeof(FFI\CData|FFI\CType $ptr): int {} - /** - * @param FFI\CData|FFI\CType $ptr - * @prefer-ref $ptr - */ - public static function alignof($ptr): int {} + /** @prefer-ref $ptr */ + public static function alignof(FFI\CData|FFI\CType $ptr): int {} /** * @param FFI\CData|string $from diff --git a/ext/ffi/ffi_arginfo.h b/ext/ffi/ffi_arginfo.h index cbeb1983fc..d9e9dec3d0 100644 --- a/ext/ffi/ffi_arginfo.h +++ b/ext/ffi/ffi_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0b4215e4686f4184b2eef0de7d60e01855725924 */ + * Stub hash: 5aeec68fea7a94cd643464acfb10bf4cfcc863da */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_cdef, 0, 0, FFI, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_STRING, 0, "\"\"") @@ -47,7 +47,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_addr, 0, 1, FFI\\CData, ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_sizeof, 0, 1, IS_LONG, 0) - ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, ptr) + ZEND_ARG_OBJ_TYPE_MASK(ZEND_SEND_PREFER_REF, ptr, FFI\\CData|FFI\\CType, 0, NULL) ZEND_END_ARG_INFO() #define arginfo_class_FFI_alignof arginfo_class_FFI_sizeof |