summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_API.c36
-rw-r--r--Zend/zend_execute.c35
-rwxr-xr-xbuild/gen_stub.php60
-rw-r--r--ext/ffi/ffi.stub.php14
-rw-r--r--ext/ffi/ffi_arginfo.h4
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