-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Make zend_type into a struct with pointer + type_mask #4728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -594,10 +594,7 @@ static void function_copy_ctor(zval *zv) /* {{{ */ | |
for (i = 0 ; i < num_args; i++) { | ||
if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { | ||
zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1); | ||
|
||
new_arg_info[i].type = | ||
ZEND_TYPE_ENCODE_CLASS( | ||
name, ZEND_TYPE_ALLOW_NULL(arg_info[i].type)); | ||
ZEND_TYPE_SET_PTR(new_arg_info[i].type, name); | ||
} | ||
} | ||
func->common.arg_info = new_arg_info + 1; | ||
|
@@ -968,7 +965,7 @@ static void zend_resolve_property_types(void) /* {{{ */ | |
zend_class_entry *prop_ce = zend_hash_find_ptr(CG(class_table), lc_type_name); | ||
|
||
ZEND_ASSERT(prop_ce && prop_ce->type == ZEND_INTERNAL_CLASS); | ||
prop_info->type = ZEND_TYPE_ENCODE_CE(prop_ce, ZEND_TYPE_ALLOW_NULL(prop_info->type)); | ||
prop_info->type = (zend_type) ZEND_TYPE_INIT_CE(prop_ce, ZEND_TYPE_ALLOW_NULL(prop_info->type), 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how modern C implements dynamic structure initializes. ZEND_TYPE_INIT_CE(rop_info->type, prop_ce, ZEND_TYPE_ALLOW_NULL(prop_info->type), 0); |
||
zend_string_release(lc_type_name); | ||
zend_string_release(type_name); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2052,21 +2052,17 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio | |
} else { | ||
internal_function->required_num_args = info->required_num_args; | ||
} | ||
if (info->return_reference) { | ||
if (ZEND_ARG_SEND_MODE(info)) { | ||
internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE; | ||
} | ||
if (ptr->arg_info[ptr->num_args].is_variadic) { | ||
if (ZEND_ARG_IS_VARIADIC(&ptr->arg_info[ptr->num_args])) { | ||
internal_function->fn_flags |= ZEND_ACC_VARIADIC; | ||
/* Don't count the variadic argument */ | ||
internal_function->num_args--; | ||
} | ||
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++; | ||
} | ||
const char *type_name = ZEND_TYPE_LITERAL_NAME(info->type); | ||
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); | ||
} | ||
|
@@ -2147,16 +2143,9 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio | |
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_string_init_interned(class_name, strlen(class_name), 1); | ||
new_arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(str, allow_null); | ||
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)); | ||
} | ||
} | ||
} | ||
|
@@ -3719,7 +3708,7 @@ ZEND_API int zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, ze | |
|
||
ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */ | ||
{ | ||
return zend_declare_typed_property(ce, name, property, access_type, doc_comment, ZEND_TYPE_ENCODE_NONE()); | ||
return zend_declare_typed_property(ce, name, property, access_type, doc_comment, (zend_type) ZEND_TYPE_INIT_NONE(0)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "big" structure is passed by value. This is not efficient. |
||
} | ||
/* }}} */ | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,34 +96,45 @@ typedef struct _zend_fcall_info_cache { | |
|
||
#define ZEND_FE_END { NULL, NULL, NULL, 0, 0 } | ||
|
||
#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_CODE(IS_ARRAY, allow_null), pass_by_ref, 0 }, | ||
#define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) { #name, ZEND_TYPE_ENCODE_CODE(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_CODE(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_ARG_VARIADIC_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, ZEND_TYPE_ENCODE_CODE(type_hint, allow_null), pass_by_ref, 1 }, | ||
#define ZEND_ARG_VARIADIC_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, ZEND_TYPE_ENCODE_CLASS_CONST(#classname, allow_null), pass_by_ref, 1 }, | ||
#define _ZEND_ARG_INFO_FLAGS(pass_by_ref, is_variadic) \ | ||
(((pass_by_ref) << _ZEND_SEND_MODE_SHIFT) | ((is_variadic) ? _ZEND_IS_VARIADIC_BIT : 0)) | ||
|
||
#define ZEND_ARG_INFO(pass_by_ref, name) \ | ||
{ #name, ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(pass_by_ref, 0))}, | ||
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CLASS_CONST(#classname, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0)) }, | ||
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CODE(IS_ARRAY, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0)) }, | ||
#define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CODE(IS_CALLABLE, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0)) }, | ||
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CODE(type_hint, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0)) }, | ||
#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) \ | ||
{ #name, ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(pass_by_ref, 1)) }, | ||
#define ZEND_ARG_VARIADIC_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CODE(type_hint, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1)) }, | ||
#define ZEND_ARG_VARIADIC_OBJ_INFO(pass_by_ref, name, classname, allow_null) \ | ||
{ #name, ZEND_TYPE_INIT_CLASS_CONST(#classname, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1)) }, | ||
|
||
#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ | ||
static const zend_internal_arg_info name[] = { \ | ||
{ (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_ENCODE_CLASS_CONST(#class_name, allow_null), return_reference, 0 }, | ||
{ (const char*)(zend_uintptr_t)(required_num_args), \ | ||
ZEND_TYPE_INIT_CLASS_CONST(#class_name, allow_null, _ZEND_ARG_INFO_FLAGS(return_reference, 0)) }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's OK to use static initializers for constants. |
||
|
||
#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO(name, class_name, allow_null) \ | ||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_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_CODE(type, allow_null), return_reference, 0 }, | ||
{ (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(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), 0, return_reference, 0 }, | ||
{ (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(return_reference, 0)) }, | ||
#define ZEND_BEGIN_ARG_INFO(name, _unused) \ | ||
ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1) | ||
ZEND_BEGIN_ARG_INFO_EX(name, {}, ZEND_RETURN_VALUE, -1) | ||
#define ZEND_END_ARG_INFO() }; | ||
|
||
/* Name macros */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1096,7 +1096,7 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop | |
} else if (ZEND_TYPE_IS_CE(type)) { | ||
str = zend_string_copy(ZEND_TYPE_CE(type)->name); | ||
} else { | ||
uint32_t type_mask = ZEND_TYPE_MASK(ZEND_TYPE_WITHOUT_NULL(type)); | ||
uint32_t type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type); | ||
switch (type_mask) { | ||
case MAY_BE_FALSE|MAY_BE_TRUE: | ||
str = ZSTR_KNOWN(ZEND_STR_BOOL); | ||
|
@@ -1160,7 +1160,7 @@ static void zend_mark_function_as_generator() /* {{{ */ | |
|| zend_string_equals_literal_ci(name, "Iterator") | ||
|| zend_string_equals_literal_ci(name, "Generator"); | ||
} else { | ||
valid_type = (ZEND_TYPE_MASK(return_info.type) & MAY_BE_ITERABLE) != 0; | ||
valid_type = (ZEND_TYPE_FULL_MASK(return_info.type) & MAY_BE_ITERABLE) != 0; | ||
} | ||
|
||
if (!valid_type) { | ||
|
@@ -2123,7 +2123,7 @@ static void zend_emit_return_type_check( | |
zend_op *opline; | ||
|
||
/* `return ...;` is illegal in a void function (but `return;` isn't) */ | ||
if (ZEND_TYPE_IS_MASK(type) && ZEND_TYPE_CONTAINS_CODE(type, IS_VOID)) { | ||
if (ZEND_TYPE_CONTAINS_CODE(type, IS_VOID)) { | ||
if (expr) { | ||
if (expr->op_type == IS_CONST && Z_TYPE(expr->u.constant) == IS_NULL) { | ||
zend_error_noreturn(E_COMPILE_ERROR, | ||
|
@@ -2149,8 +2149,7 @@ static void zend_emit_return_type_check( | |
} | ||
|
||
if (expr && expr->op_type == IS_CONST) { | ||
if (ZEND_TYPE_IS_MASK(type) | ||
&& ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) { | ||
if (ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) { | ||
/* we don't need run-time check */ | ||
return; | ||
} | ||
|
@@ -5289,11 +5288,11 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */ | |
n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM); | ||
i = 0; | ||
while (i < n) { | ||
ZEND_SET_ARG_FLAG(func, i + 1, func->common.arg_info[i].pass_by_reference); | ||
ZEND_SET_ARG_FLAG(func, i + 1, ZEND_ARG_SEND_MODE(&func->common.arg_info[i])); | ||
i++; | ||
} | ||
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_VARIADIC && func->common.arg_info[i].pass_by_reference)) { | ||
uint32_t pass_by_reference = func->common.arg_info[i].pass_by_reference; | ||
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_VARIADIC && ZEND_ARG_SEND_MODE(&func->common.arg_info[i]))) { | ||
uint32_t pass_by_reference = ZEND_ARG_SEND_MODE(&func->common.arg_info[i]); | ||
while (i < MAX_ARG_FLAG_NUM) { | ||
ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference); | ||
i++; | ||
|
@@ -5312,7 +5311,7 @@ static zend_type zend_compile_typename(zend_ast *ast, zend_bool force_allow_null | |
} | ||
|
||
if (ast->kind == ZEND_AST_TYPE) { | ||
return ZEND_TYPE_ENCODE_CODE(ast->attr, allow_null); | ||
return (zend_type) ZEND_TYPE_INIT_CODE(ast->attr, allow_null, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return "big" structure by value is not efficient. |
||
} else { | ||
zend_string *class_name = zend_ast_get_str(ast); | ||
zend_uchar type = zend_lookup_builtin_type_by_name(class_name); | ||
|
@@ -5326,7 +5325,7 @@ static zend_type zend_compile_typename(zend_ast *ast, zend_bool force_allow_null | |
if (type == IS_VOID && allow_null) { | ||
zend_error_noreturn(E_COMPILE_ERROR, "Void type cannot be nullable"); | ||
} | ||
return ZEND_TYPE_ENCODE_CODE(type, allow_null); | ||
return (zend_type) ZEND_TYPE_INIT_CODE(type, allow_null, 0); | ||
} else { | ||
uint32_t fetch_type = zend_get_class_fetch_type_ast(ast); | ||
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) { | ||
|
@@ -5337,7 +5336,7 @@ static zend_type zend_compile_typename(zend_ast *ast, zend_bool force_allow_null | |
zend_string_addref(class_name); | ||
} | ||
|
||
return ZEND_TYPE_ENCODE_CLASS(class_name, allow_null); | ||
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, allow_null, 0); | ||
} | ||
} | ||
} | ||
|
@@ -5356,11 +5355,11 @@ static zend_bool zend_is_valid_default_value(zend_type type, zval *value) | |
if (ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE_P(value))) { | ||
return 1; | ||
} | ||
if ((ZEND_TYPE_MASK(type) & MAY_BE_DOUBLE) && Z_TYPE_P(value) == IS_LONG) { | ||
if ((ZEND_TYPE_FULL_MASK(type) & MAY_BE_DOUBLE) && Z_TYPE_P(value) == IS_LONG) { | ||
/* Integers are allowed as initializers for floating-point values. */ | ||
return 1; | ||
} | ||
if ((ZEND_TYPE_MASK(type) & MAY_BE_ITERABLE) && Z_TYPE_P(value) == IS_ARRAY) { | ||
if ((ZEND_TYPE_FULL_MASK(type) & MAY_BE_ITERABLE) && Z_TYPE_P(value) == IS_ARRAY) { | ||
return 1; | ||
} | ||
return 0; | ||
|
@@ -5377,9 +5376,9 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ | |
/* 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 = zend_compile_typename(return_type_ast, 0); | ||
ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS( | ||
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0); | ||
arg_infos++; | ||
op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; | ||
} else { | ||
|
@@ -5451,23 +5450,18 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ | |
|
||
arg_info = &arg_infos[i]; | ||
arg_info->name = zend_string_copy(name); | ||
arg_info->pass_by_reference = is_ref; | ||
arg_info->is_variadic = is_variadic; | ||
arg_info->type = ZEND_TYPE_ENCODE_NONE(); | ||
arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0); | ||
|
||
if (type_ast) { | ||
uint32_t default_type = default_ast ? Z_TYPE(default_node.u.constant) : IS_UNDEF; | ||
|
||
uint32_t arg_type; | ||
zend_bool is_class; | ||
|
||
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; | ||
arg_info->type = zend_compile_typename(type_ast, default_type == IS_NULL); | ||
|
||
is_class = ZEND_TYPE_IS_CLASS(arg_info->type); | ||
arg_type = !is_class ? ZEND_TYPE_MASK(arg_info->type) : 0; | ||
|
||
if (arg_type & MAY_BE_VOID) { | ||
if (!is_class && (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_VOID)) { | ||
zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type"); | ||
} | ||
|
||
|
@@ -5485,6 +5479,8 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ | |
opline->extended_value = zend_alloc_cache_slot(); | ||
} | ||
} | ||
|
||
ZEND_TYPE_FULL_MASK(arg_info->type) |= _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic); | ||
} | ||
|
||
/* These are assigned at the end to avoid uninitialized memory in case of an error */ | ||
|
@@ -5984,13 +5980,12 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags) / | |
zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); | ||
zend_string *doc_comment = NULL; | ||
zval value_zv; | ||
zend_type type = ZEND_TYPE_ENCODE_NONE(); | ||
zend_type type = ZEND_TYPE_INIT_NONE(0); | ||
|
||
if (type_ast) { | ||
type = zend_compile_typename(type_ast, 0); | ||
|
||
if (ZEND_TYPE_IS_MASK(type) | ||
&& (ZEND_TYPE_MASK(type) & (MAY_BE_VOID|MAY_BE_CALLABLE))) { | ||
if (ZEND_TYPE_FULL_MASK(type) & (MAY_BE_VOID|MAY_BE_CALLABLE)) { | ||
zend_string *str = zend_type_to_string(type); | ||
zend_error_noreturn(E_COMPILE_ERROR, | ||
"Property %s::$%s cannot have type %s", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to name macro ZEND_TYPE_SET_CLASS_NAME()