diff options
author | Dmitry Stogov <dmitry@zend.com> | 2017-01-13 11:37:46 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2017-01-13 11:37:46 +0300 |
commit | 141d1ba9801f742dc5d9ccd06e02b94284c4deb7 (patch) | |
tree | cc9d1730b73a2b147d14857bb967e6d55df5af90 | |
parent | 28391c30ca008013267592ab2a2eebce3da3f3b0 (diff) | |
download | php-git-141d1ba9801f742dc5d9ccd06e02b94284c4deb7.tar.gz |
Introduced "zend_type" - an abstraction for type-hinting representation.
-rw-r--r-- | Zend/zend_API.c | 47 | ||||
-rw-r--r-- | Zend/zend_API.h | 30 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 4 | ||||
-rw-r--r-- | Zend/zend_compile.c | 103 | ||||
-rw-r--r-- | Zend/zend_compile.h | 12 | ||||
-rw-r--r-- | Zend/zend_execute.c | 242 | ||||
-rw-r--r-- | Zend/zend_inheritance.c | 69 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 21 | ||||
-rw-r--r-- | Zend/zend_types.h | 58 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 8 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 40 | ||||
-rw-r--r-- | ext/com_dotnet/com_handlers.c | 2 | ||||
-rw-r--r-- | ext/opcache/Optimizer/dfa_pass.c | 4 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 28 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 6 | ||||
-rw-r--r-- | ext/opcache/ZendAccelerator.c | 16 | ||||
-rw-r--r-- | ext/opcache/zend_file_cache.c | 22 | ||||
-rw-r--r-- | ext/opcache/zend_persist.c | 8 | ||||
-rw-r--r-- | ext/opcache/zend_persist_calc.c | 8 | ||||
-rw-r--r-- | ext/reflection/php_reflection.c | 88 |
20 files changed, 413 insertions, 403 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e0c7396cdc..bbea611697 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2187,11 +2187,15 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio /* Don't count the variadic argument */ internal_function->num_args--; } - if (info->type_hint) { - if (info->class_name) { - ZEND_ASSERT(info->type_hint == IS_OBJECT); - if (!scope && (!strcasecmp(info->class_name, "self") || !strcasecmp(info->class_name, "parent"))) { - zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", info->class_name); + if (ZEND_TYPE_IS_SET(info->type)) { + if (ZEND_TYPE_IS_CLASS(info->type)) { + const char *type_name = (const char*)info->type; + + if (type_name[0] == '?') { + type_name++; + } + if (!scope && (!strcasecmp(type_name, "self") || !strcasecmp(type_name, "parent"))) { + zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", type_name); } } @@ -2248,14 +2252,43 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio if (reg_function->common.arg_info && reg_function->common.num_args) { uint32_t i; for (i = 0; i < reg_function->common.num_args; i++) { - if (reg_function->common.arg_info[i].class_name || - reg_function->common.arg_info[i].type_hint) { + if (ZEND_TYPE_IS_SET(reg_function->common.arg_info[i].type)) { reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; break; } } } + if (reg_function->common.arg_info && + (reg_function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + /* convert "const char*" class type names into "zend_string*" */ + uint32_t i; + uint32_t num_args = reg_function->common.num_args + 1; + zend_arg_info *arg_info = reg_function->common.arg_info - 1; + zend_arg_info *new_arg_info; + + if (reg_function->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + new_arg_info = malloc(sizeof(zend_arg_info) * num_args); + memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); + reg_function->common.arg_info = new_arg_info + 1; + for (i = 0; i < num_args; i++) { + if (ZEND_TYPE_IS_CLASS(new_arg_info[i].type)) { + const char *class_name = (const char*)new_arg_info[i].type; + zend_bool allow_null = 0; + zend_string *str; + + if (class_name[0] == '?') { + class_name++; + allow_null = 1; + } + str = zend_new_interned_string(zend_string_init(class_name, strlen(class_name), 1)); + new_arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(str, allow_null); + } + } + } + if (scope) { /* Look for ctor, dtor, clone * If it's an old-style constructor, store it only if we don't have diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 704779346a..55f5e55d62 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -97,24 +97,30 @@ typedef struct _zend_fcall_info_cache { #define ZEND_FE_END { NULL, NULL, NULL, 0, 0 } -#define ZEND_ARG_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, NULL, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, #classname, IS_OBJECT, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_ARRAY, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_CALLABLE, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, NULL, type_hint, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 1 }, +#define ZEND_ARG_INFO(pass_by_ref, name) { #name, 0, pass_by_ref, 0}, +#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, pass_by_ref, 0}, +#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, ZEND_TYPE_ENCODE_CLASS_CONST(#classname, allow_null), pass_by_ref, 0 }, +#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, ZEND_TYPE_ENCODE(IS_ARRAY, allow_null), pass_by_ref, 0 }, +#define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) { #name, ZEND_TYPE_ENCODE(IS_CALLABLE, allow_null), pass_by_ref, 0 }, +#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, ZEND_TYPE_ENCODE(type_hint, allow_null), pass_by_ref, 0 }, +#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, 0, pass_by_ref, 1 }, -#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, class_name, allow_null) \ +#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, classname, allow_null) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), class_name, type, return_reference, allow_null, 0 }, -#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(name, type, class_name, allow_null) \ - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, -1, type, class_name, allow_null) + { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE_CLASS_CONST(#classname, allow_null), return_reference, 0 }, +#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO(name, class_name, allow_null) \ + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, -1, class_name, allow_null) + +#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ + static const zend_internal_arg_info name[] = { \ + { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE(type, allow_null), return_reference, 0 }, +#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(name, type, allow_null) \ + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, 0, -1, type, allow_null) #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), NULL, 0, return_reference, 0, 0 }, + { (const char*)(zend_uintptr_t)(required_num_args), 0, return_reference, 0 }, #define ZEND_BEGIN_ARG_INFO(name, _unused) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() }; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f94467239c..40ab240a8c 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -256,9 +256,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1) ZEND_END_ARG_INFO() #if ZEND_DEBUG -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func, IS_ARRAY, NULL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func, IS_ARRAY, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func2, IS_ARRAY, NULL, 1) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func2, IS_ARRAY, 1) ZEND_END_ARG_INFO() #endif diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 488920b006..c289fefb9e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1274,17 +1274,17 @@ static void zend_mark_function_as_generator() /* {{{ */ if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { zend_arg_info return_info = CG(active_op_array)->arg_info[-1]; - if (return_info.type_hint != IS_ITERABLE) { + if (ZEND_TYPE_CODE(return_info.type) != IS_ITERABLE) { const char *msg = "Generators may only declare a return type of Generator, Iterator, Traversable, or iterable, %s is not permitted"; - if (!return_info.class_name) { - zend_error_noreturn(E_COMPILE_ERROR, msg, zend_get_type_by_const(return_info.type_hint)); + if (!ZEND_TYPE_IS_CLASS(return_info.type)) { + zend_error_noreturn(E_COMPILE_ERROR, msg, zend_get_type_by_const(ZEND_TYPE_CODE(return_info.type))); } - if (!zend_string_equals_literal_ci(return_info.class_name, "Traversable") - && !zend_string_equals_literal_ci(return_info.class_name, "Iterator") - && !zend_string_equals_literal_ci(return_info.class_name, "Generator")) { - zend_error_noreturn(E_COMPILE_ERROR, msg, ZSTR_VAL(return_info.class_name)); + if (!zend_string_equals_literal_ci(ZEND_TYPE_NAME(return_info.type), "Traversable") + && !zend_string_equals_literal_ci(ZEND_TYPE_NAME(return_info.type), "Iterator") + && !zend_string_equals_literal_ci(ZEND_TYPE_NAME(return_info.type), "Generator")) { + zend_error_noreturn(E_COMPILE_ERROR, msg, ZSTR_VAL(ZEND_TYPE_NAME(return_info.type))); } } } @@ -2323,26 +2323,26 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ static void zend_emit_return_type_check( znode *expr, zend_arg_info *return_info, zend_bool implicit) /* {{{ */ { - /* `return ...;` is illegal in a void function (but `return;` isn't) */ - if (return_info->type_hint == IS_VOID) { - if (expr) { - if (expr->op_type == IS_CONST && Z_TYPE(expr->u.constant) == IS_NULL) { - zend_error_noreturn(E_COMPILE_ERROR, - "A void function must not return a value " - "(did you mean \"return;\" instead of \"return null;\"?)"); - } else { - zend_error_noreturn(E_COMPILE_ERROR, "A void function must not return a value"); + if (ZEND_TYPE_IS_SET(return_info->type)) { + zend_op *opline; + + /* `return ...;` is illegal in a void function (but `return;` isn't) */ + if (ZEND_TYPE_CODE(return_info->type) == IS_VOID) { + if (expr) { + if (expr->op_type == IS_CONST && Z_TYPE(expr->u.constant) == IS_NULL) { + zend_error_noreturn(E_COMPILE_ERROR, + "A void function must not return a value " + "(did you mean \"return;\" instead of \"return null;\"?)"); + } else { + zend_error_noreturn(E_COMPILE_ERROR, "A void function must not return a value"); + } } + /* we don't need run-time check */ + return; } - /* we don't need run-time check */ - return; - } - - if (return_info->type_hint != IS_UNDEF) { - zend_op *opline; if (!expr && !implicit) { - if (return_info->allow_null) { + if (ZEND_TYPE_ALLOW_NULL(return_info->type)) { zend_error_noreturn(E_COMPILE_ERROR, "A function with return type must return a value " "(did you mean \"return null;\" instead of \"return;\"?)"); @@ -2353,11 +2353,11 @@ static void zend_emit_return_type_check( } if (expr && expr->op_type == IS_CONST) { - if ((return_info->type_hint == Z_TYPE(expr->u.constant)) - ||((return_info->type_hint == _IS_BOOL) + if ((ZEND_TYPE_CODE(return_info->type) == Z_TYPE(expr->u.constant)) + ||((ZEND_TYPE_CODE(return_info->type) == _IS_BOOL) && (Z_TYPE(expr->u.constant) == IS_FALSE || Z_TYPE(expr->u.constant) == IS_TRUE)) - || (return_info->allow_null + || (ZEND_TYPE_ALLOW_NULL(return_info->type) && Z_TYPE(expr->u.constant) == IS_NULL)) { /* we don't need run-time check */ return; @@ -2369,7 +2369,7 @@ static void zend_emit_return_type_check( opline->result_type = expr->op_type = IS_TMP_VAR; opline->result.var = expr->u.op.var = get_temporary_variable(CG(active_op_array)); } - if (return_info->class_name) { + if (ZEND_TYPE_IS_CLASS(return_info->type)) { opline->op2.num = CG(active_op_array)->cache_size; CG(active_op_array)->cache_size += sizeof(void*); } else { @@ -5038,10 +5038,10 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */ } /* }}} */ -static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{ */ +static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info, zend_bool allow_null) /* {{{ */ { if (ast->kind == ZEND_AST_TYPE) { - arg_info->type_hint = ast->attr; + arg_info->type = ZEND_TYPE_ENCODE(ast->attr, allow_null); } else { zend_string *class_name = zend_ast_get_str(ast); zend_uchar type = zend_lookup_builtin_type_by_name(class_name); @@ -5052,7 +5052,7 @@ static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{ "Scalar type declaration '%s' must be unqualified", ZSTR_VAL(zend_string_tolower(class_name))); } - arg_info->type_hint = type; + arg_info->type = ZEND_TYPE_ENCODE(type, allow_null); } else { uint32_t fetch_type = zend_get_class_fetch_type_ast(ast); if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) { @@ -5063,8 +5063,7 @@ static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{ zend_string_addref(class_name); } - arg_info->type_hint = IS_OBJECT; - arg_info->class_name = class_name; + arg_info->type = ZEND_TYPE_ENCODE_CLASS(class_name, allow_null); } } } @@ -5078,23 +5077,23 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_arg_info *arg_infos; if (return_type_ast) { + zend_bool allow_null = 0; + /* Use op_array->arg_info[-1] for return type */ arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children + 1, 0); arg_infos->name = NULL; arg_infos->pass_by_reference = (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; arg_infos->is_variadic = 0; - arg_infos->type_hint = 0; - arg_infos->allow_null = 0; - arg_infos->class_name = NULL; + arg_infos->type = 0; if (return_type_ast->attr & ZEND_TYPE_NULLABLE) { - arg_infos->allow_null = 1; + allow_null = 1; return_type_ast->attr &= ~ZEND_TYPE_NULLABLE; } - zend_compile_typename(return_type_ast, arg_infos); + zend_compile_typename(return_type_ast, arg_infos, allow_null); - if (arg_infos->type_hint == IS_VOID && arg_infos->allow_null) { + if (ZEND_TYPE_CODE(arg_infos->type) == IS_VOID && ZEND_TYPE_ALLOW_NULL(arg_infos->type)) { zend_error_noreturn(E_COMPILE_ERROR, "Void type cannot be nullable"); } @@ -5171,11 +5170,11 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ arg_info->name = zend_string_copy(name); arg_info->pass_by_reference = is_ref; arg_info->is_variadic = is_variadic; - arg_info->type_hint = 0; - arg_info->allow_null = 1; - arg_info->class_name = NULL; + /* TODO: Keep compatibility, but may be better reset "allow_null" ??? */ + arg_info->type = ZEND_TYPE_ENCODE(0, 1); if (type_ast) { + zend_bool allow_null; zend_bool has_null_default = default_ast && (Z_TYPE(default_node.u.constant) == IS_NULL || (Z_TYPE(default_node.u.constant) == IS_CONSTANT @@ -5183,17 +5182,17 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_bool is_explicitly_nullable = (type_ast->attr & ZEND_TYPE_NULLABLE) == ZEND_TYPE_NULLABLE; op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; - arg_info->allow_null = has_null_default || is_explicitly_nullable; + allow_null = has_null_default || is_explicitly_nullable; type_ast->attr &= ~ZEND_TYPE_NULLABLE; - zend_compile_typename(type_ast, arg_info); + zend_compile_typename(type_ast, arg_info, allow_null); - if (arg_info->type_hint == IS_VOID) { + if (ZEND_TYPE_CODE(arg_info->type) == IS_VOID) { zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type"); } if (type_ast->kind == ZEND_AST_TYPE) { - if (arg_info->type_hint == IS_ARRAY) { + if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) { if (default_ast && !has_null_default && Z_TYPE(default_node.u.constant) != IS_ARRAY && !Z_CONSTANT(default_node.u.constant) @@ -5201,7 +5200,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with array type can only be an array or NULL"); } - } else if (arg_info->type_hint == IS_CALLABLE && default_ast) { + } else if (ZEND_TYPE_CODE(arg_info->type) == IS_CALLABLE && default_ast) { if (!has_null_default && !Z_CONSTANT(default_node.u.constant)) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with callable type can only be NULL"); @@ -5209,10 +5208,10 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } } else { if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) { - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with a class type can only be NULL"); - } else switch (arg_info->type_hint) { + } else switch (ZEND_TYPE_CODE(arg_info->type)) { case IS_DOUBLE: if (Z_TYPE(default_node.u.constant) != IS_DOUBLE && Z_TYPE(default_node.u.constant) != IS_LONG) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " @@ -5228,10 +5227,10 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ break; default: - if (!ZEND_SAME_FAKE_TYPE(arg_info->type_hint, Z_TYPE(default_node.u.constant))) { + if (!ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(arg_info->type), Z_TYPE(default_node.u.constant))) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with a %s type can only be %s or NULL", - zend_get_type_by_const(arg_info->type_hint), zend_get_type_by_const(arg_info->type_hint)); + zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)), zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type))); } break; } @@ -5240,13 +5239,13 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ /* Allocate cache slot to speed-up run-time class resolution */ if (opline->opcode == ZEND_RECV_INIT) { - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { zend_alloc_cache_slot(opline->op2.constant); } else { Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1; } } else { - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { opline->op2.num = op_array->cache_size; op_array->cache_size += sizeof(void*); } else { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d848a2a35e..5018602a1f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -322,20 +322,16 @@ typedef struct _zend_class_constant { /* arg_info for internal functions */ typedef struct _zend_internal_arg_info { const char *name; - const char *class_name; - zend_uchar type_hint; + zend_type type; zend_uchar pass_by_reference; - zend_bool allow_null; zend_bool is_variadic; } zend_internal_arg_info; /* arg_info for user functions */ typedef struct _zend_arg_info { zend_string *name; - zend_string *class_name; - zend_uchar type_hint; + zend_type type; zend_uchar pass_by_reference; - zend_bool allow_null; zend_bool is_variadic; } zend_arg_info; @@ -346,10 +342,8 @@ typedef struct _zend_arg_info { */ typedef struct _zend_internal_function_info { zend_uintptr_t required_num_args; - const char *class_name; - zend_uchar type_hint; + zend_type type; zend_bool return_reference; - zend_bool allow_null; zend_bool _is_variadic; } zend_internal_function_info; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3ad663445b..ad788aff44 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -607,25 +607,6 @@ static inline int make_real_object(zval *object) return 1; } -static zend_class_entry *zend_verify_internal_arg_class_kind( - const zend_internal_arg_info *cur_arg_info) -{ - zend_string *key; - zend_class_entry *ce; - ALLOCA_FLAG(use_heap); - - ZSTR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap); - ce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); - ZSTR_ALLOCA_FREE(key, use_heap); - - return ce; -} - -static zend_always_inline zend_class_entry* zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info) -{ - return zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); -} - static ZEND_COLD void zend_verify_type_error_common( const zend_function *zf, const zend_arg_info *arg_info, const zend_class_entry *ce, zval *value, @@ -644,46 +625,46 @@ static ZEND_COLD void zend_verify_type_error_common( *fclass = ""; } - switch (arg_info->type_hint) { - case IS_OBJECT: - if (ce) { - if (ce->ce_flags & ZEND_ACC_INTERFACE) { - *need_msg = "implement interface "; - is_interface = 1; - } else { - *need_msg = "be an instance of "; - } - *need_kind = ZSTR_VAL(ce->name); + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { + if (ce) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + *need_msg = "implement interface "; + is_interface = 1; } else { - /* We don't know whether it's a class or interface, assume it's a class */ *need_msg = "be an instance of "; - *need_kind = zf->common.type == ZEND_INTERNAL_FUNCTION - ? ((zend_internal_arg_info *) arg_info)->class_name - : ZSTR_VAL(arg_info->class_name); } - break; - case IS_CALLABLE: - *need_msg = "be callable"; - *need_kind = ""; - break; - case IS_ITERABLE: - *need_msg = "be iterable"; - *need_kind = ""; - break; - default: - *need_msg = "be of the type "; - *need_kind = zend_get_type_by_const(arg_info->type_hint); - break; + *need_kind = ZSTR_VAL(ce->name); + } else { + /* We don't know whether it's a class or interface, assume it's a class */ + + *need_msg = "be an instance of "; + *need_kind = ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type)); + } + } else { + switch (ZEND_TYPE_CODE(arg_info->type)) { + case IS_CALLABLE: + *need_msg = "be callable"; + *need_kind = ""; + break; + case IS_ITERABLE: + *need_msg = "be iterable"; + *need_kind = ""; + break; + default: + *need_msg = "be of the type "; + *need_kind = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)); + break; + } } - if (arg_info->allow_null) { + if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { *need_or_null = is_interface ? " or be null" : " or null"; } else { *need_or_null = ""; } if (value) { - if (arg_info->type_hint == IS_OBJECT && Z_TYPE_P(value) == IS_OBJECT) { + if (ZEND_TYPE_IS_CLASS(arg_info->type) && Z_TYPE_P(value) == IS_OBJECT) { *given_msg = "instance of "; *given_kind = ZSTR_VAL(Z_OBJCE_P(value)->name); } else { @@ -803,137 +784,48 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, z return zend_verify_weak_scalar_type_hint(type_hint, arg); } -static zend_always_inline zend_bool zend_check_internal_type( - const zend_function *zf, const zend_internal_arg_info *arg_info, - zval *arg, zend_class_entry **ce, zend_bool is_return_type) -{ - if (!arg_info->type_hint) { - return 1; - } - - ZVAL_DEREF(arg); - if (EXPECTED(arg_info->type_hint == Z_TYPE_P(arg))) { - if (arg_info->class_name) { - *ce = zend_verify_internal_arg_class_kind(arg_info); - return *ce && instanceof_function(Z_OBJCE_P(arg), *ce); - } - return 1; - } - - if (Z_TYPE_P(arg) == IS_NULL && arg_info->allow_null) { - return 1; - } - - if (arg_info->class_name) { - *ce = zend_verify_internal_arg_class_kind(arg_info); - return 0; - } else if (arg_info->type_hint == IS_CALLABLE) { - return zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL); - } else if (arg_info->type_hint == IS_ITERABLE) { - return zend_is_iterable(arg); - } else if (arg_info->type_hint == _IS_BOOL && - EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) { - return 1; - } else if (is_return_type) { - /* Internal return types are always strict */ - return 0; - } else { - /* Internal parameter types honor strict_types */ - return zend_verify_scalar_type_hint(arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))); - } -} - -static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) -{ - const zend_internal_arg_info *cur_arg_info; - zend_class_entry *ce = NULL; - - if (EXPECTED(arg_num <= zf->internal_function.num_args)) { - cur_arg_info = &zf->internal_function.arg_info[arg_num-1]; - } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) { - cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args]; - } else { - return 1; - } - - if (UNEXPECTED(!zend_check_internal_type(zf, cur_arg_info, arg, &ce, 0))) { - zend_verify_arg_error(zf, (const zend_arg_info *) cur_arg_info, arg_num, ce, arg); - return 0; - } - - return 1; -} - -static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call) -{ - uint32_t i; - uint32_t num_args = ZEND_CALL_NUM_ARGS(call); - zval *p = ZEND_CALL_ARG(call, 1); - - for (i = 0; i < num_args; ++i) { - if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - return 0; - } - p++; - } - return 1; -} - static zend_always_inline zend_bool zend_check_type( - const zend_function *zf, const zend_arg_info *arg_info, + zend_type type, zval *arg, zend_class_entry **ce, void **cache_slot, - zval *default_value, zend_bool is_return_type) + zval *default_value, zend_class_entry *scope, + zend_bool is_return_type) { - if (!arg_info->type_hint) { + if (!ZEND_TYPE_IS_SET(type)) { return 1; } ZVAL_DEREF(arg); - if (EXPECTED(arg_info->type_hint == Z_TYPE_P(arg))) { - if (arg_info->class_name) { - if (EXPECTED(*cache_slot)) { - *ce = (zend_class_entry *) *cache_slot; - } else { - *ce = zend_verify_arg_class_kind(arg_info); - if (UNEXPECTED(!*ce)) { - return 0; - } - *cache_slot = (void *) *ce; - } - if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(arg), *ce))) { + if (ZEND_TYPE_IS_CLASS(type)) { + if (EXPECTED(*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)) { return 0; } + *cache_slot = (void *) *ce; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { + return instanceof_function(Z_OBJCE_P(arg), *ce); } + } else if (EXPECTED(ZEND_TYPE_CODE(type) == Z_TYPE_P(arg))) { return 1; } - if (Z_TYPE_P(arg) == IS_NULL && (arg_info->allow_null || (default_value && is_null_constant(zf->common.scope, default_value)))) { + if (Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)))) { /* Null passed to nullable type */ return 1; } - if (UNEXPECTED(arg_info->class_name)) { - /* This is always an error - we fetch the class name for the error message here */ - if (EXPECTED(*cache_slot)) { - *ce = (zend_class_entry *) *cache_slot; - } else { - *ce = zend_verify_arg_class_kind(arg_info); - if (*ce) { - *cache_slot = (void *) *ce; - } - } - return 0; - } else if (arg_info->type_hint == IS_CALLABLE) { + if (ZEND_TYPE_CODE(type) == IS_CALLABLE) { return zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL); - } else if (arg_info->type_hint == IS_ITERABLE) { + } else if (ZEND_TYPE_CODE(type) == IS_ITERABLE) { return zend_is_iterable(arg); - } else if (arg_info->type_hint == _IS_BOOL && + } else if (ZEND_TYPE_CODE(type) == _IS_BOOL && EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) { return 1; } else { - return zend_verify_scalar_type_hint(arg_info->type_hint, arg, + return zend_verify_scalar_type_hint(ZEND_TYPE_CODE(type), arg, is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES()); } @@ -954,7 +846,7 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a return 1; } - if (UNEXPECTED(!zend_check_type(zf, cur_arg_info, arg, &ce, cache_slot, default_value, 0))) { + if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg); return 0; } @@ -962,6 +854,25 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a return 1; } +static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call) +{ + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + void *dummy_cache_slot; + + for (i = 0; i < num_args; ++i) { + dummy_cache_slot = NULL; + if (UNEXPECTED(!zend_verify_arg_type(fbc, i + 1, p, NULL, &dummy_cache_slot))) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + return 0; + } + p++; + } + return 1; +} + ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data) { zend_execute_data *ptr = EX(prev_execute_data); @@ -1040,13 +951,14 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret) { zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; zend_class_entry *ce = NULL; + void *dummy_cache_slot = NULL; - if (UNEXPECTED(ret_info->type_hint == IS_VOID && Z_TYPE_P(ret) != IS_NULL)) { + if (UNEXPECTED(ZEND_TYPE_CODE(ret_info->type) == IS_VOID && Z_TYPE_P(ret) != IS_NULL)) { zend_verify_void_return_error(zf, zend_zval_type_name(ret), ""); return 0; } - if (UNEXPECTED(!zend_check_internal_type(zf, ret_info, ret, &ce, 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, NULL, 1))) { zend_verify_internal_return_error(zf, ce, ret); return 0; } @@ -1060,7 +972,7 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval * zend_arg_info *ret_info = zf->common.arg_info - 1; zend_class_entry *ce = NULL; - if (UNEXPECTED(!zend_check_type(zf, ret_info, ret, &ce, cache_slot, NULL, 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, NULL, 1))) { zend_verify_return_error(zf, ce, ret); } } @@ -1069,13 +981,13 @@ static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **c { zend_arg_info *ret_info = zf->common.arg_info - 1; - if (ret_info->type_hint && UNEXPECTED(ret_info->type_hint != IS_VOID)) { + if (ZEND_TYPE_IS_SET(ret_info->type) && UNEXPECTED(ZEND_TYPE_CODE(ret_info->type) != IS_VOID)) { zend_class_entry *ce = NULL; - if (ret_info->class_name) { + if (ZEND_TYPE_IS_CLASS(ret_info->type)) { if (EXPECTED(*cache_slot)) { ce = (zend_class_entry*) *cache_slot; } else { - ce = zend_verify_arg_class_kind(ret_info); + ce = zend_fetch_class(ZEND_TYPE_NAME(ret_info->type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (ce) { *cache_slot = (void*)ce; } @@ -3072,7 +2984,7 @@ ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_e ZEND_API void ZEND_FASTCALL zend_check_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) { - zend_verify_internal_arg_type(zf, arg_num, arg); + zend_verify_arg_type(zf, arg_num, arg, NULL, NULL); } ZEND_API int ZEND_FASTCALL zend_check_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index fd1345f844..9f64162e81 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -169,11 +169,11 @@ char *zend_visibility_string(uint32_t fn_flags) /* {{{ */ static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_info *arg_info) /* {{{ */ { - if (arg_info->type_hint == IS_ARRAY) { + if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) { return 1; } - if (arg_info->class_name && zend_string_equals_literal_ci(arg_info->class_name, "Traversable")) { + if (ZEND_TYPE_IS_CLASS(arg_info->type) && zend_string_equals_literal_ci(ZEND_TYPE_NAME(arg_info->type), "Traversable")) { return 1; } @@ -183,47 +183,33 @@ static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_i static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */ { - if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) { + if (ZEND_LOG_XOR(ZEND_TYPE_IS_CLASS(fe_arg_info->type), ZEND_TYPE_IS_CLASS(proto_arg_info->type))) { /* Only one has a type declaration and the other one doesn't */ return 0; } - if (fe_arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(fe_arg_info->type)) { zend_string *fe_class_name, *proto_class_name; const char *class_name; - if (fe->type == ZEND_INTERNAL_FUNCTION) { - fe_class_name = NULL; - class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name; - } else { - fe_class_name = fe_arg_info->class_name; - class_name = ZSTR_VAL(fe_arg_info->class_name); - } + fe_class_name = ZEND_TYPE_NAME(fe_arg_info->type); + class_name = ZSTR_VAL(fe_class_name); if (!strcasecmp(class_name, "parent") && proto->common.scope) { fe_class_name = zend_string_copy(proto->common.scope->name); } else if (!strcasecmp(class_name, "self") && fe->common.scope) { fe_class_name = zend_string_copy(fe->common.scope->name); - } else if (fe_class_name) { - zend_string_addref(fe_class_name); } else { - fe_class_name = zend_string_init(class_name, strlen(class_name), 0); + zend_string_addref(fe_class_name); } - if (proto->type == ZEND_INTERNAL_FUNCTION) { - proto_class_name = NULL; - class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name; - } else { - proto_class_name = proto_arg_info->class_name; - class_name = ZSTR_VAL(proto_arg_info->class_name); - } + proto_class_name = ZEND_TYPE_NAME(proto_arg_info->type); + class_name = ZSTR_VAL(proto_class_name); if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) { proto_class_name = zend_string_copy(proto->common.scope->parent->name); } else if (!strcasecmp(class_name, "self") && proto->common.scope) { proto_class_name = zend_string_copy(proto->common.scope->name); - } else if (proto_class_name) { - zend_string_addref(proto_class_name); } else { - proto_class_name = zend_string_init(class_name, strlen(class_name), 0); + zend_string_addref(proto_class_name); } if (strcasecmp(ZSTR_VAL(fe_class_name), ZSTR_VAL(proto_class_name)) != 0) { @@ -250,9 +236,7 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf } zend_string_release(proto_class_name); zend_string_release(fe_class_name); - } - - if (fe_arg_info->type_hint != proto_arg_info->type_hint) { + } else if (ZEND_TYPE_CODE(fe_arg_info->type) != ZEND_TYPE_CODE(proto_arg_info->type)) { /* Incompatible type */ return 0; } @@ -330,7 +314,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c } if (!zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) { - switch (fe_arg_info->type_hint) { + switch (ZEND_TYPE_CODE(fe_arg_info->type)) { case IS_ITERABLE: if (!zend_iterable_compatibility_check(proto_arg_info)) { return 0; @@ -343,7 +327,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c } // This introduces BC break described at https://bugs.php.net/bug.php?id=72119 - if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) { + if (ZEND_TYPE_IS_SET(proto_arg_info->type) && ZEND_TYPE_ALLOW_NULL(proto_arg_info->type) && !ZEND_TYPE_ALLOW_NULL(fe_arg_info->type)) { /* incompatible nullability */ return 0; } @@ -363,7 +347,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c } if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) { - switch (proto->common.arg_info[-1].type_hint) { + switch (ZEND_TYPE_CODE(proto->common.arg_info[-1].type)) { case IS_ITERABLE: if (!zend_iterable_compatibility_check(fe->common.arg_info - 1)) { return 0; @@ -375,7 +359,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c } } - if (fe->common.arg_info[-1].allow_null && !proto->common.arg_info[-1].allow_null) { + if (ZEND_TYPE_ALLOW_NULL(fe->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(proto->common.arg_info[-1].type)) { return 0; } } @@ -386,21 +370,16 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function *fptr, zend_arg_info *arg_info, int return_hint) /* {{{ */ { - if (arg_info->type_hint != IS_UNDEF && arg_info->allow_null) { + if (ZEND_TYPE_IS_SET(arg_info->type) && ZEND_TYPE_ALLOW_NULL(arg_info->type)) { smart_str_appendc(str, '?'); } - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { const char *class_name; size_t class_name_len; - if (fptr->type == ZEND_INTERNAL_FUNCTION) { - class_name = ((zend_internal_arg_info*)arg_info)->class_name; - class_name_len = strlen(class_name); - } else { - class_name = ZSTR_VAL(arg_info->class_name); - class_name_len = ZSTR_LEN(arg_info->class_name); - } + class_name = ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type)); + class_name_len = ZSTR_LEN(ZEND_TYPE_NAME(arg_info->type)); if (!strcasecmp(class_name, "self") && fptr->common.scope) { class_name = ZSTR_VAL(fptr->common.scope->name); @@ -414,13 +393,13 @@ static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function if (!return_hint) { smart_str_appendc(str, ' '); } - } else if (arg_info->type_hint) { - if (arg_info->type_hint == IS_LONG) { + } else if (ZEND_TYPE_IS_CODE(arg_info->type)) { + if (ZEND_TYPE_CODE(arg_info->type) == IS_LONG) { smart_str_appendl(str, "int", 3); - } else if (arg_info->type_hint == _IS_BOOL) { + } else if (ZEND_TYPE_CODE(arg_info->type) == _IS_BOOL) { smart_str_appendl(str, "bool", 4); } else { - const char *type_name = zend_get_type_by_const(arg_info->type_hint); + const char *type_name = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)); smart_str_appends(str, type_name); } if (!return_hint) { @@ -628,7 +607,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) || - (child->common.arg_info[-1].allow_null && !parent->common.arg_info[-1].allow_null))) { + (ZEND_TYPE_ALLOW_NULL(child->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(parent->common.arg_info[-1].type)))) { error_level = E_COMPILE_ERROR; error_verb = "must"; } else { diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 1719094e9a..438feb4c91 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -110,6 +110,23 @@ ZEND_API void destroy_zend_function(zend_function *function) ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(function->common.function_name); zend_string_release(function->common.function_name); + + if (function->common.arg_info && + (function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + uint32_t i; + uint32_t num_args = function->common.num_args + 1; + zend_arg_info *arg_info = function->common.arg_info - 1; + + if (function->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + for (i = 0 ; i < num_args; i++) { + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_string_release(ZEND_TYPE_NAME(arg_info[i].type)); + } + } + free(arg_info); + } } } @@ -433,8 +450,8 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (arg_info[i].name) { zend_string_release(arg_info[i].name); } - if (arg_info[i].class_name) { - zend_string_release(arg_info[i].class_name); + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_string_release(ZEND_TYPE_NAME(arg_info[i].type)); } } efree(arg_info); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 1b52d150d3..76bb594671 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -98,6 +98,64 @@ typedef void (*sort_func_t)(void *, size_t, size_t, compare_func_t, swap_func_t) typedef void (*dtor_func_t)(zval *pDest); typedef void (*copy_ctor_func_t)(zval *pElement); +/* + * zend_type - is an abstraction layer to represent information about type hint. + * It shouldn't be used directly. Only through ZEND_TYPE_* macros. + * + * ZEND_TYPE_IS_SET() - checks if type-hint exists + * ZEND_TYPE_IS_CODE() - checks if type-hint refer to standard type + * ZEND_TYPE_IS_CLASS() - checks if type-hint refer to some class + * + * ZEND_TYPE_NAME() - returns referenced class name + * ZEND_TYPE_CE() - returns referenced class entry + * ZEND_TYPE_CODE() - returns standard type code (e.g. IS_LONG, _IS_BOOL) + * + * ZEND_TYPE_ALLOW_NULL() - checks if NULL is allowed + * + * ZEND_TYPE_ENCODE() and ZEND_TYPE_ENCODE_CLASS() should be used for + * construction. + */ + +typedef uintptr_t zend_type; + +#define ZEND_TYPE_IS_SET(t) \ + ((t) > Z_L(1)) + +#define ZEND_TYPE_IS_CODE(t) \ + (((t) > Z_L(1)) && ((t) <= Z_L(0x1ff))) + +#define ZEND_TYPE_IS_CLASS(t) \ + ((t) > Z_L(0x1ff)) + +#define ZEND_TYPE_NAME(t) \ + ((zend_string*)((t) & ~Z_L(0x3))) + +#define ZEND_TYPE_CE(t) \ + ((zend_class_entry*)((t) & ~Z_L(0x3))) + +#define ZEND_TYPE_CODE(t) \ + ((t) >> Z_L(1)) + +#define ZEND_TYPE_ALLOW_NULL(t) \ + (((t) & Z_L(0x1)) != 0) + +#define ZEND_TYPE_ENCODE(code, allow_null) \ + (((code) << Z_L(1)) | ((allow_null) ? Z_L(0x1) : Z_L(0x0))) + +#define ZEND_TYPE_ENCODE_CLASS(class_name, allow_null) \ + (((uintptr_t)(class_name)) | ((allow_null) ? Z_L(0x1) : Z_L(0))) + +#define ZEND_TYPE_ENCODE_CLASS_CONST_0(class_name) \ + ((zend_type) class_name) +#define ZEND_TYPE_ENCODE_CLASS_CONST_1(class_name) \ + ((zend_type) "?" class_name) +#define ZEND_TYPE_ENCODE_CLASS_CONST_Q2(macro, class_name) \ + macro(class_name) +#define ZEND_TYPE_ENCODE_CLASS_CONST_Q1(allow_null, class_name) \ + ZEND_TYPE_ENCODE_CLASS_CONST_Q2(ZEND_TYPE_ENCODE_CLASS_CONST_ ##allow_null, class_name) +#define ZEND_TYPE_ENCODE_CLASS_CONST(class_name, allow_null) \ + ZEND_TYPE_ENCODE_CLASS_CONST_Q1(allow_null, class_name) + typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 930fffb04e..569e1c0717 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3796,10 +3796,10 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a02f8be0dc..f6ebd5f297 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7686,10 +7686,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_ ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { @@ -14410,10 +14410,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { @@ -21425,10 +21425,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { @@ -29118,10 +29118,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { @@ -40446,10 +40446,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU ZVAL_DEREF(retval_ptr); } - if (UNEXPECTED(!ret_info->class_name - && ret_info->type_hint != IS_CALLABLE - && ret_info->type_hint != IS_ITERABLE - && !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)) + if (UNEXPECTED(!ZEND_TYPE_IS_CLASS(ret_info->type) + && ZEND_TYPE_CODE(ret_info->type) != IS_CALLABLE + && ZEND_TYPE_CODE(ret_info->type) != IS_ITERABLE + && !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(retval_ptr)) && !(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) && retval_ref != retval_ptr) ) { diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 9597ce1007..3eebad0ef1 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -302,7 +302,7 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info)); for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) { - f.arg_info[i].allow_null = 1; + f.arg_info[i].type = ZEND_TYPE_ENCODE(0,1);; if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) { f.arg_info[i].pass_by_reference = ZEND_SEND_BY_REF; } diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 55915e70a9..63f7fafa93 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -321,11 +321,11 @@ static inline zend_bool can_elide_return_type_check( return 0; } - if (info->type_hint == IS_CALLABLE) { + if (ZEND_TYPE_CODE(info->type) == IS_CALLABLE) { return 0; } - if (info->class_name) { + if (ZEND_TYPE_IS_CLASS(info->type)) { if (!use_info->ce || !def_info->ce || !instanceof_function(use_info->ce, def_info->ce)) { return 0; } diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 9ecf71ea83..069074d3bf 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1323,13 +1323,13 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int return 1; } else if (op_array->arg_info && opline->op1.num <= op_array->num_args) { - if (op_array->arg_info[opline->op1.num-1].type_hint == IS_LONG) { + if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == IS_LONG) { tmp->underflow = 0; tmp->min = ZEND_LONG_MIN; tmp->max = ZEND_LONG_MAX; tmp->overflow = 0; return 1; - } else if (op_array->arg_info[opline->op1.num-1].type_hint == _IS_BOOL) { + } else if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == _IS_BOOL) { tmp->underflow = 0; tmp->min = 0; tmp->max = 1; @@ -2087,31 +2087,33 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar uint32_t tmp = 0; *pce = NULL; - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { // class type hinting... - zend_string *lcname = zend_string_tolower(arg_info->class_name); + zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(arg_info->type)); tmp |= MAY_BE_OBJECT; *pce = get_class_entry(script, lcname); zend_string_release(lcname); - } else if (arg_info->type_hint != IS_UNDEF) { - if (arg_info->type_hint == IS_VOID) { + } else if (ZEND_TYPE_IS_CODE(arg_info->type)) { + zend_uchar type_hint = ZEND_TYPE_CODE(arg_info->type); + + if (type_hint == IS_VOID) { tmp |= MAY_BE_NULL; - } else if (arg_info->type_hint == IS_CALLABLE) { + } else if (type_hint == IS_CALLABLE) { tmp |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (arg_info->type_hint == IS_ITERABLE) { + } else if (type_hint == IS_ITERABLE) { tmp |= MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (arg_info->type_hint == IS_ARRAY) { + } else if (type_hint == IS_ARRAY) { tmp |= MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (arg_info->type_hint == _IS_BOOL) { + } else if (type_hint == _IS_BOOL) { tmp |= MAY_BE_TRUE|MAY_BE_FALSE; } else { - ZEND_ASSERT(arg_info->type_hint < IS_REFERENCE); - tmp |= 1 << arg_info->type_hint; + ZEND_ASSERT(type_hint < IS_REFERENCE); + tmp |= 1 << type_hint; } } else { tmp |= MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; } - if (arg_info->allow_null) { + if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { tmp |= MAY_BE_NULL; } return tmp; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index a30f18479a..ee659fa2f2 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -506,9 +506,9 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, } case ZEND_VERIFY_RETURN_TYPE: { zend_arg_info *ret_info = op_array->arg_info - 1; - if (ret_info->class_name - || ret_info->type_hint == IS_CALLABLE - || !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(val)) + if (ZEND_TYPE_IS_CLASS(ret_info->type) + || ZEND_TYPE_CODE(ret_info->type) == IS_CALLABLE + || !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(val)) || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) { zval_dtor(val); return 0; diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 8be645be65..634e1151aa 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -537,6 +537,22 @@ static void accel_use_shm_interned_strings(void) if (Z_FUNC(p->val)->common.function_name) { Z_FUNC(p->val)->common.function_name = accel_new_interned_string(Z_FUNC(p->val)->common.function_name); } + if (Z_FUNC(p->val)->common.arg_info && + (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + uint32_t i; + uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1; + zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1; + + if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + for (i = 0 ; i < num_args; i++) { + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type); + arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(accel_new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)), allow_null); + } + } + } } /* class table hash keys, class names, properties, methods, constants, etc */ diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index c9ae0dd66e..9e99dd6221 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -436,8 +436,15 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra if (!IS_SERIALIZED(p->name)) { SERIALIZE_STR(p->name); } - if (!IS_SERIALIZED(p->class_name)) { - SERIALIZE_STR(p->class_name); + if (ZEND_TYPE_IS_CLASS(p->type)) { + zend_string *type_name = ZEND_TYPE_NAME(p->type); + + if (!IS_SERIALIZED(type_name)) { + zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(p->type); + + SERIALIZE_STR(type_name); + p->type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null); + } } p++; } @@ -1011,8 +1018,15 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr if (!IS_UNSERIALIZED(p->name)) { UNSERIALIZE_STR(p->name); } - if (!IS_UNSERIALIZED(p->class_name)) { - UNSERIALIZE_STR(p->class_name); + if (ZEND_TYPE_IS_CLASS(p->type)) { + zend_string *type_name = ZEND_TYPE_NAME(p->type); + + if (!IS_UNSERIALIZED(type_name)) { + zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(p->type); + + UNSERIALIZE_STR(type_name); + p->type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null); + } } p++; } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 5eeea6c056..e67184f757 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -492,8 +492,12 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc if (arg_info[i].name) { zend_accel_store_interned_string(arg_info[i].name); } - if (arg_info[i].class_name) { - zend_accel_store_interned_string(arg_info[i].class_name); + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_string *type_name = ZEND_TYPE_NAME(arg_info[i].type); + zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type); + + zend_accel_store_interned_string(type_name); + arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null); } } } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index e597373edd..f169dffad1 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -230,8 +230,12 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) if (arg_info[i].name) { ADD_INTERNED_STRING(arg_info[i].name, 1); } - if (arg_info[i].class_name) { - ADD_INTERNED_STRING(arg_info[i].class_name, 1); + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_string *type_name = ZEND_TYPE_NAME(arg_info[i].type); + zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type); + + ADD_INTERNED_STRING(type_name, 1); + arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null); } } } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0757e75f29..9c465d78d4 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -603,18 +603,15 @@ static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_ } else { smart_str_append_printf(str, "<required> "); } - if (arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { smart_str_append_printf(str, "%s ", - (fptr->type == ZEND_INTERNAL_FUNCTION && - !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? - ((zend_internal_arg_info*)arg_info)->class_name : - ZSTR_VAL(arg_info->class_name)); - if (arg_info->allow_null) { + ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type))); + if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { smart_str_append_printf(str, "or NULL "); } - } else if (arg_info->type_hint) { - smart_str_append_printf(str, "%s ", zend_get_type_by_const(arg_info->type_hint)); - if (arg_info->allow_null) { + } else if (ZEND_TYPE_IS_CODE(arg_info->type)) { + smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type))); + if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { smart_str_append_printf(str, "or NULL "); } } @@ -825,18 +822,15 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent smart_str_free(¶m_indent); if (fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { smart_str_append_printf(str, " %s- Return [ ", indent); - if (fptr->common.arg_info[-1].class_name) { + if (ZEND_TYPE_IS_CLASS(fptr->common.arg_info[-1].type)) { smart_str_append_printf(str, "%s ", - (fptr->type == ZEND_INTERNAL_FUNCTION && - !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? - ((zend_internal_arg_info*)(fptr->common.arg_info - 1))->class_name : - ZSTR_VAL(fptr->common.arg_info[-1].class_name)); - if (fptr->common.arg_info[-1].allow_null) { + ZSTR_VAL(ZEND_TYPE_NAME(fptr->common.arg_info[-1].type))); + if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) { smart_str_appends(str, "or NULL "); } - } else if (fptr->common.arg_info[-1].type_hint) { - smart_str_append_printf(str, "%s ", zend_get_type_by_const(fptr->common.arg_info[-1].type_hint)); - if (fptr->common.arg_info[-1].allow_null) { + } else if (ZEND_TYPE_IS_CODE(fptr->common.arg_info[-1].type)) { + smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(fptr->common.arg_info[-1].type))); + if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) { smart_str_appends(str, "or NULL "); } } @@ -2551,7 +2545,7 @@ ZEND_METHOD(reflection_parameter, getClass) } GET_REFLECTION_OBJECT_PTR(param); - if (param->arg_info->class_name) { + if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) { /* Class name is stored as a string, we might also get "self" or "parent" * - For "self", simply use the function scope. If scope is NULL then * the function is global and thus self does not make any sense @@ -2564,25 +2558,17 @@ ZEND_METHOD(reflection_parameter, getClass) * TODO: Think about moving these checks to the compiler or some sort of * lint-mode. */ - const char *class_name; - size_t class_name_len; + zend_string *class_name; - if (param->fptr->type == ZEND_INTERNAL_FUNCTION && - !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - class_name = ((zend_internal_arg_info*)param->arg_info)->class_name; - class_name_len = strlen(class_name); - } else { - class_name = ZSTR_VAL(param->arg_info->class_name); - class_name_len = ZSTR_LEN(param->arg_info->class_name); - } - if (0 == zend_binary_strcasecmp(class_name, class_name_len, "self", sizeof("self")- 1)) { + class_name = ZEND_TYPE_NAME(param->arg_info->type); + if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "self", sizeof("self")- 1)) { ce = param->fptr->common.scope; if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Parameter uses 'self' as type hint but function is not a class member!"); return; } - } else if (0 == zend_binary_strcasecmp(class_name, class_name_len, "parent", sizeof("parent")- 1)) { + } else if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "parent", sizeof("parent")- 1)) { ce = param->fptr->common.scope; if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0, @@ -2596,17 +2582,10 @@ ZEND_METHOD(reflection_parameter, getClass) } ce = ce->parent; } else { - if (param->fptr->type == ZEND_INTERNAL_FUNCTION && - !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - zend_string *name = zend_string_init(class_name, class_name_len, 0); - ce = zend_lookup_class(name); - zend_string_release(name); - } else { - ce = zend_lookup_class(param->arg_info->class_name); - } + ce = zend_lookup_class(class_name); if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Class %s does not exist", class_name); + "Class %s does not exist", ZSTR_VAL(class_name)); return; } } @@ -2627,7 +2606,7 @@ ZEND_METHOD(reflection_parameter, hasType) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->type_hint != 0); + RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type)); } /* }}} */ @@ -2643,11 +2622,7 @@ ZEND_METHOD(reflection_parameter, getType) } GET_REFLECTION_OBJECT_PTR(param); - if (((param->fptr->type == ZEND_INTERNAL_FUNCTION && - !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? - ((zend_internal_arg_info*)param->arg_info)->type_hint : - param->arg_info->type_hint) == 0) - { + if (!ZEND_TYPE_IS_SET(param->arg_info->type)) { RETURN_NULL(); } reflection_type_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value); @@ -2666,7 +2641,7 @@ ZEND_METHOD(reflection_parameter, isArray) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->type_hint == IS_ARRAY); + RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_ARRAY); } /* }}} */ @@ -2682,7 +2657,7 @@ ZEND_METHOD(reflection_parameter, isCallable) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->type_hint == IS_CALLABLE); + RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_CALLABLE); } /* }}} */ @@ -2698,7 +2673,7 @@ ZEND_METHOD(reflection_parameter, allowsNull) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->allow_null); + RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type)); } /* }}} */ @@ -2897,7 +2872,7 @@ ZEND_METHOD(reflection_type, allowsNull) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->allow_null); + RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type)); } /* }}} */ @@ -2913,21 +2888,18 @@ ZEND_METHOD(reflection_type, isBuiltin) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->type_hint != IS_OBJECT); + RETVAL_BOOL(ZEND_TYPE_IS_CODE(param->arg_info->type)); } /* }}} */ /* {{{ reflection_type_name */ static zend_string *reflection_type_name(type_reference *param) { - switch (param->arg_info->type_hint) { + if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) { + return zend_string_copy(ZEND_TYPE_NAME(param->arg_info->type)); + } + switch (ZEND_TYPE_CODE(param->arg_info->type)) { case IS_ARRAY: return zend_string_init("array", sizeof("array") - 1, 0); case IS_CALLABLE: return zend_string_init("callable", sizeof("callable") - 1, 0); - case IS_OBJECT: - if (param->fptr->type == ZEND_INTERNAL_FUNCTION && - !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - return zend_string_init(((zend_internal_arg_info*)param->arg_info)->class_name, strlen(((zend_internal_arg_info*)param->arg_info)->class_name), 0); - } - return zend_string_copy(param->arg_info->class_name); case IS_STRING: return zend_string_init("string", sizeof("string") - 1, 0); case _IS_BOOL: return zend_string_init("bool", sizeof("bool") - 1, 0); case IS_LONG: return zend_string_init("int", sizeof("int") - 1, 0); |