Skip to content

Commit 08eca9c

Browse files
committed
Introduced struct zend_attribute. Defer ASt evaluation to access time.
1 parent bc2f4f7 commit 08eca9c

File tree

4 files changed

+195
-223
lines changed

4 files changed

+195
-223
lines changed

Zend/zend_attributes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
#include "zend_API.h"
33
#include "zend_attributes.h"
44

5-
void zend_attribute_validate_phpattribute(zval *attribute, int target)
5+
void zend_attribute_validate_phpattribute(zend_attribute *attr, int target)
66
{
77
if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
88
zend_error(E_COMPILE_ERROR, "Only classes can be marked with <<PhpAttribute>>");
99
}
1010
}
1111

12-
void zend_attribute_validate_phpcompilerattribute(zval *attribute, int target)
12+
void zend_attribute_validate_phpcompilerattribute(zend_attribute *attr, int target)
1313
{
1414
zend_error(E_COMPILE_ERROR, "The PhpCompilerAttribute can only be used by internal classes, use PhpAttribute instead");
1515
}

Zend/zend_attributes.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,43 @@
1212
zend_class_entry *zend_ce_php_attribute;
1313
zend_class_entry *zend_ce_php_compiler_attribute;
1414

15-
typedef void (*zend_attributes_internal_validator)(zval *attribute, int target);
15+
typedef struct _zend_attribute {
16+
zend_string *name;
17+
zend_string *lcname;
18+
uint32_t offset;
19+
uint32_t argc;
20+
zval argv[1];
21+
} zend_attribute;
22+
23+
static zend_always_inline zend_bool zend_has_attribute(HashTable *attributes, zend_string *name, uint32_t offset)
24+
{
25+
if (attributes) {
26+
zend_attribute *attr;
27+
28+
ZEND_HASH_FOREACH_PTR(attributes, attr) {
29+
if (attr->offset == offset && zend_string_equals(attr->lcname, name)) {
30+
return 1;
31+
}
32+
} ZEND_HASH_FOREACH_END();
33+
}
34+
35+
return 0;
36+
}
37+
38+
static zend_always_inline zend_bool zend_has_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
39+
{
40+
zend_bool result = 0;
41+
42+
if (attributes) {
43+
zend_string *name = zend_string_init(str, len, 0);
44+
result = zend_has_attribute(attributes, name, offset);
45+
zend_string_release(name);
46+
}
47+
48+
return result;
49+
}
50+
51+
typedef void (*zend_attributes_internal_validator)(zend_attribute *attr, int target);
1652
HashTable zend_attributes_internal_validators;
1753

1854
void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator);

Zend/zend_compile.c

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5717,89 +5717,81 @@ static zend_bool zend_is_valid_default_value(zend_type type, zval *value)
57175717
return 0;
57185718
}
57195719

5720-
static void zend_compile_attribute(zval *v, zend_ast *ast) /* {{{ */
5720+
static zend_attribute *zend_compile_attribute(zend_ast *ast, uint32_t offset) /* {{{ */
57215721
{
57225722
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE);
57235723

5724-
array_init_size(v, 1 + (ast->child[1] ? zend_ast_get_list(ast->child[1])->children : 0));
5725-
add_next_index_str(v, zend_resolve_class_name_ast(ast->child[0]));
5724+
zend_ast_list *list = ast->child[1] ? zend_ast_get_list(ast->child[1]) : NULL;
5725+
zend_attribute *attr = emalloc(sizeof(zend_attribute) + sizeof(zval) * (list ? list->children : 0));
57265726

5727-
if (ast->child[1]) {
5728-
zend_ast_list *list = zend_ast_get_list(ast->child[1]);
5729-
uint32_t i;
5730-
zval tmp;
5727+
attr->name = zend_resolve_class_name_ast(ast->child[0]);
5728+
attr->lcname = zend_string_tolower(attr->name);
5729+
attr->offset = offset;
5730+
attr->argc = list ? list->children : 0;
57315731

5732+
if (ast->child[1]) {
57325733
ZEND_ASSERT(ast->child[1]->kind == ZEND_AST_ARG_LIST);
57335734

5734-
ZVAL_NULL(&tmp);
5735+
uint32_t i;
57355736

57365737
for (i = 0; i < list->children; i++) {
5737-
zend_const_expr_to_zval(zend_hash_next_index_insert(Z_ARRVAL_P(v), &tmp), list->child[i]);
5738+
zend_const_expr_to_zval(&attr->argv[i], list->child[i]);
57385739
}
57395740
}
5741+
5742+
return attr;
57405743
}
57415744
/* }}} */
57425745

5743-
static HashTable *zend_compile_attributes(zend_ast *ast, int target) /* {{{ */
5746+
static void attribute_ptr_dtor(zval *v) /* {{{ */
57445747
{
5745-
HashTable *attr;
5746-
5747-
zend_ast_list *list = zend_ast_get_list(ast);
5748+
zend_attribute *attr = Z_PTR_P(v);
57485749
uint32_t i;
57495750

5750-
zval tmp;
5751-
5752-
ZVAL_NULL(&tmp);
5751+
zend_string_release(attr->name);
5752+
zend_string_release(attr->lcname);
57535753

5754-
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
5755-
5756-
ALLOC_HASHTABLE(attr);
5757-
zend_hash_init(attr, zend_ast_get_list(ast)->children, NULL, ZVAL_PTR_DTOR, 0);
5758-
5759-
for (i = 0; i < list->children; i++) {
5760-
zend_ast *el = list->child[i];
5761-
zend_string *name;
5754+
for (i = 0; i < attr->argc; i++) {
5755+
zval_ptr_dtor(&attr->argv[i]);
5756+
}
57625757

5763-
zval a;
5764-
zval *x;
5758+
efree(attr);
5759+
}
5760+
/* }}} */
57655761

5766-
zend_compile_attribute(&a, el);
5762+
static zend_always_inline HashTable *create_attribute_array(uint32_t size) /* {{{ */
5763+
{
5764+
HashTable *attributes;
57675765

5768-
name = zend_string_tolower(Z_STR_P(zend_hash_index_find(Z_ARRVAL(a), 0)));
5769-
x = zend_hash_find(attr, name);
5766+
ALLOC_HASHTABLE(attributes);
5767+
zend_hash_init(attributes, size, NULL, attribute_ptr_dtor, 0);
57705768

5771-
// Validate internal attribute
5772-
zend_attributes_internal_validator validator = zend_hash_find_ptr(&zend_attributes_internal_validators, name);
5769+
return attributes;
5770+
}
5771+
/* }}} */
57735772

5774-
if (validator != NULL) {
5775-
validator(&a, target);
5776-
}
5773+
static void zend_compile_attributes(HashTable *attributes, zend_ast *ast, uint32_t offset, int target) /* {{{ */
5774+
{
5775+
zend_ast_list *list = zend_ast_get_list(ast);
5776+
uint32_t i;
57775777

5778-
if (x) {
5779-
ZEND_ASSERT(Z_TYPE_P(x) == IS_ARRAY);
5778+
zval tmp;
57805779

5781-
if (Z_TYPE_P(zend_hash_index_find(Z_ARRVAL_P(x), 0)) == IS_ARRAY) {
5782-
add_next_index_zval(x, &a);
5783-
} else {
5784-
zval array;
5780+
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
57855781

5786-
ZEND_ASSERT(Z_TYPE_P(zend_hash_index_find(Z_ARRVAL_P(x), 0)) == IS_STRING);
5782+
for (i = 0; i < list->children; i++) {
5783+
zend_attribute *attr = zend_compile_attribute(list->child[i], 0);
57875784

5788-
Z_ADDREF_P(x);
5785+
// Validate internal attribute
5786+
zend_attributes_internal_validator validator = zend_hash_find_ptr(&zend_attributes_internal_validators, attr->lcname);
57895787

5790-
array_init(&array);
5791-
add_next_index_zval(&array, x);
5792-
add_next_index_zval(&array, &a);
5793-
zend_hash_update(attr, name, &array);
5794-
}
5795-
} else {
5796-
zend_hash_add(attr, name, &a);
5788+
if (validator != NULL) {
5789+
validator(attr, target);
57975790
}
57985791

5799-
zend_string_release(name);
5792+
ZVAL_PTR(&tmp, attr);
5793+
zend_hash_next_index_insert(attributes, &tmp);
58005794
}
5801-
5802-
return attr;
58035795
}
58045796
/* }}} */
58055797

@@ -5908,15 +5900,11 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
59085900
arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0);
59095901

59105902
if (attributes_ast) {
5911-
zval attr;
5912-
59135903
if (!op_array->attributes) {
5914-
ALLOC_HASHTABLE(op_array->attributes);
5915-
zend_hash_init(op_array->attributes, 8, NULL, ZVAL_PTR_DTOR, 0);
5904+
op_array->attributes = create_attribute_array(zend_ast_get_list(attributes_ast)->children);
59165905
}
59175906

5918-
ZVAL_ARR(&attr, zend_compile_attributes(attributes_ast, ZEND_ATTRIBUTE_TARGET_PARAMETER));
5919-
zend_hash_index_add(op_array->attributes, i, &attr);
5907+
zend_compile_attributes(op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER);
59205908
}
59215909

59225910
if (type_ast) {
@@ -6376,10 +6364,12 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
63766364
}
63776365
if (decl->attributes) {
63786366
int target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
6367+
63796368
if (is_method) {
63806369
target = ZEND_ATTRIBUTE_TARGET_METHOD;
63816370
}
6382-
op_array->attributes = zend_compile_attributes(decl->attributes, target);
6371+
op_array->attributes = create_attribute_array(zend_ast_get_list(decl->attributes)->children);
6372+
zend_compile_attributes(op_array->attributes, decl->attributes, 0, target);
63836373
}
63846374
if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) {
63856375
op_array->fn_flags |= ZEND_ACC_CLOSURE;
@@ -6548,12 +6538,15 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, H
65486538

65496539
void zend_compile_prop_group(zend_ast *list) /* {{{ */
65506540
{
6551-
HashTable *attributes;
6541+
HashTable *attributes = NULL;
65526542

65536543
zend_ast *type_ast = list->child[0];
65546544
zend_ast *prop_ast = list->child[1];
65556545

6556-
attributes = list->child[2] ? zend_compile_attributes(list->child[2], ZEND_ATTRIBUTE_TARGET_PROPERTY) : NULL;
6546+
if (list->child[2]) {
6547+
attributes = create_attribute_array(zend_ast_get_list(list->child[2])->children);
6548+
zend_compile_attributes(attributes, list->child[2], 0, ZEND_ATTRIBUTE_TARGET_PROPERTY);
6549+
}
65576550

65586551
zend_compile_prop_decl(prop_ast, type_ast, list->attr, attributes);
65596552

@@ -6579,15 +6572,18 @@ void zend_compile_class_const_decl(zend_ast *ast, zend_ast *attr_ast) /* {{{ */
65796572
{
65806573
zend_ast_list *list = zend_ast_get_list(ast);
65816574
zend_class_entry *ce = CG(active_class_entry);
6582-
HashTable *attributes;
6575+
HashTable *attributes = NULL;
65836576
uint32_t i;
65846577

65856578
if ((ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
65866579
zend_error_noreturn(E_COMPILE_ERROR, "Traits cannot have constants");
65876580
return;
65886581
}
65896582

6590-
attributes = attr_ast ? zend_compile_attributes(attr_ast, ZEND_ATTRIBUTE_TARGET_CLASS_CONST) : NULL;
6583+
if (attr_ast) {
6584+
attributes = create_attribute_array(zend_ast_get_list(attr_ast)->children);
6585+
zend_compile_attributes(attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
6586+
}
65916587

65926588
for (i = 0; i < list->children; ++i) {
65936589
zend_ast *const_ast = list->child[i];
@@ -6818,7 +6814,8 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
68186814
ce->info.user.doc_comment = zend_string_copy(decl->doc_comment);
68196815
}
68206816
if (decl->attributes) {
6821-
ce->info.user.attributes = zend_compile_attributes(decl->attributes, ZEND_ATTRIBUTE_TARGET_CLASS);
6817+
ce->info.user.attributes = create_attribute_array(zend_ast_get_list(decl->attributes)->children);
6818+
zend_compile_attributes(ce->info.user.attributes, decl->attributes, 0, ZEND_ATTRIBUTE_TARGET_CLASS);
68226819
}
68236820

68246821
if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) {

0 commit comments

Comments
 (0)