Skip to content

Commit 39ded1d

Browse files
committed
Changed zend_ast_ref structure to use only one allocation, removing dichotomy between heap/arena ASTs.
1 parent 65f610b commit 39ded1d

8 files changed

+94
-56
lines changed

UPGRADING.INTERNALS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ PHP 7.2 INTERNALS UPGRADE NOTES
1313
j. Run-time constant operand addressing
1414
k. Array/Object recursion protection
1515
l. HASH_FLAG_PERSISTENT
16+
m. zend_ast_ref
1617

1718
2. Build system changes
1819
a. Unix build system changes
@@ -88,6 +89,11 @@ PHP 7.2 INTERNALS UPGRADE NOTES
8889
l. HASH_FLAG_PERSISTENT renamed into IS_ARRAY_PERSISTENT and moved into
8990
GC_FLAGS (to be consistent with IS_STR_PERSISTENT).
9091

92+
m. zend_ast_ref structure is changed to use only one allocation.
93+
zend_ast_copy() now returns zend_ast_ref (instead of zend_asr).
94+
zend_ast_destroy_and_free() is removed. ZVAL_NEW_AST() is replaced
95+
by ZVAL_AST().
96+
9197
========================
9298
2. Build system changes
9399
========================

Zend/zend_ast.c

Lines changed: 71 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -451,40 +451,92 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc
451451
return ret;
452452
}
453453

454-
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
454+
static size_t zend_ast_tree_size(zend_ast *ast)
455455
{
456-
if (ast == NULL) {
457-
return NULL;
458-
} else if (ast->kind == ZEND_AST_ZVAL) {
459-
zend_ast_zval *new = emalloc(sizeof(zend_ast_zval));
456+
size_t size;
457+
458+
if (ast->kind == ZEND_AST_ZVAL) {
459+
size = sizeof(zend_ast_zval);
460+
} else if (zend_ast_is_list(ast)) {
461+
uint32_t i;
462+
zend_ast_list *list = zend_ast_get_list(ast);
463+
464+
size = zend_ast_list_size(list->children);
465+
for (i = 0; i < list->children; i++) {
466+
if (list->child[i]) {
467+
size += zend_ast_tree_size(list->child[i]);
468+
}
469+
}
470+
} else {
471+
uint32_t i, children = zend_ast_get_num_children(ast);
472+
473+
size = zend_ast_size(children);
474+
for (i = 0; i < children; i++) {
475+
if (ast->child[i]) {
476+
size += zend_ast_tree_size(ast->child[i]);
477+
}
478+
}
479+
}
480+
return size;
481+
}
482+
483+
static void* zend_ast_tree_copy(zend_ast *ast, void *buf)
484+
{
485+
if (ast->kind == ZEND_AST_ZVAL) {
486+
zend_ast_zval *new = (zend_ast_zval*)buf;
460487
new->kind = ZEND_AST_ZVAL;
461488
new->attr = ast->attr;
462489
ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
463-
return (zend_ast *) new;
490+
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
464491
} else if (zend_ast_is_list(ast)) {
465492
zend_ast_list *list = zend_ast_get_list(ast);
466-
zend_ast_list *new = emalloc(zend_ast_list_size(list->children));
493+
zend_ast_list *new = (zend_ast_list*)buf;
467494
uint32_t i;
468495
new->kind = list->kind;
469496
new->attr = list->attr;
470497
new->children = list->children;
498+
buf = (void*)((char*)buf + zend_ast_list_size(list->children));
471499
for (i = 0; i < list->children; i++) {
472-
new->child[i] = zend_ast_copy(list->child[i]);
500+
if (list->child[i]) {
501+
new->child[i] = (zend_ast*)buf;
502+
buf = zend_ast_tree_copy(list->child[i], buf);
503+
} else {
504+
new->child[i] = NULL;
505+
}
473506
}
474-
return (zend_ast *) new;
475507
} else {
476508
uint32_t i, children = zend_ast_get_num_children(ast);
477-
zend_ast *new = emalloc(zend_ast_size(children));
509+
zend_ast *new = (zend_ast*)buf;
478510
new->kind = ast->kind;
479511
new->attr = ast->attr;
512+
buf = (void*)((char*)buf + zend_ast_size(children));
480513
for (i = 0; i < children; i++) {
481-
new->child[i] = zend_ast_copy(ast->child[i]);
514+
if (ast->child[i]) {
515+
new->child[i] = (zend_ast*)buf;
516+
buf = zend_ast_tree_copy(ast->child[i], buf);
517+
} else {
518+
new->child[i] = NULL;
519+
}
482520
}
483-
return new;
484521
}
522+
return buf;
485523
}
486524

487-
static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
525+
ZEND_API zend_ast_ref *zend_ast_copy(zend_ast *ast)
526+
{
527+
size_t tree_size;
528+
zend_ast_ref *ref;
529+
530+
ZEND_ASSERT(ast != NULL);
531+
tree_size = zend_ast_tree_size(ast) + sizeof(zend_ast_ref);
532+
ref = emalloc(tree_size);
533+
zend_ast_tree_copy(ast, GC_AST(ref));
534+
GC_REFCOUNT(ref) = 1;
535+
GC_TYPE_INFO(ref) = IS_CONSTANT_AST;
536+
return ref;
537+
}
538+
539+
ZEND_API void zend_ast_destroy(zend_ast *ast) {
488540
if (!ast) {
489541
return;
490542
}
@@ -508,37 +560,26 @@ static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
508560
if (decl->doc_comment) {
509561
zend_string_release(decl->doc_comment);
510562
}
511-
zend_ast_destroy_ex(decl->child[0], free);
512-
zend_ast_destroy_ex(decl->child[1], free);
513-
zend_ast_destroy_ex(decl->child[2], free);
514-
zend_ast_destroy_ex(decl->child[3], free);
563+
zend_ast_destroy(decl->child[0]);
564+
zend_ast_destroy(decl->child[1]);
565+
zend_ast_destroy(decl->child[2]);
566+
zend_ast_destroy(decl->child[3]);
515567
break;
516568
}
517569
default:
518570
if (zend_ast_is_list(ast)) {
519571
zend_ast_list *list = zend_ast_get_list(ast);
520572
uint32_t i;
521573
for (i = 0; i < list->children; i++) {
522-
zend_ast_destroy_ex(list->child[i], free);
574+
zend_ast_destroy(list->child[i]);
523575
}
524576
} else {
525577
uint32_t i, children = zend_ast_get_num_children(ast);
526578
for (i = 0; i < children; i++) {
527-
zend_ast_destroy_ex(ast->child[i], free);
579+
zend_ast_destroy(ast->child[i]);
528580
}
529581
}
530582
}
531-
532-
if (free) {
533-
efree(ast);
534-
}
535-
}
536-
537-
ZEND_API void zend_ast_destroy(zend_ast *ast) {
538-
zend_ast_destroy_ex(ast, 0);
539-
}
540-
ZEND_API void zend_ast_destroy_and_free(zend_ast *ast) {
541-
zend_ast_destroy_ex(ast, 1);
542583
}
543584

544585
ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {

Zend/zend_ast.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,8 @@ ZEND_API zend_ast *zend_ast_list_add(zend_ast *list, zend_ast *op);
206206
ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope);
207207
ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix);
208208

209-
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast);
209+
ZEND_API zend_ast_ref *zend_ast_copy(zend_ast *ast);
210210
ZEND_API void zend_ast_destroy(zend_ast *ast);
211-
ZEND_API void zend_ast_destroy_and_free(zend_ast *ast);
212211

213212
typedef void (*zend_ast_apply_func)(zend_ast **ast_ptr);
214213
ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn);

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8040,7 +8040,7 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */
80408040
if (ast->kind == ZEND_AST_ZVAL) {
80418041
ZVAL_COPY_VALUE(result, zend_ast_get_zval(ast));
80428042
} else {
8043-
ZVAL_NEW_AST(result, zend_ast_copy(ast));
8043+
ZVAL_AST(result, zend_ast_copy(ast));
80448044
/* destroy the ast here, it might have been replaced */
80458045
zend_ast_destroy(ast);
80468046
}

Zend/zend_types.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ struct _zend_reference {
355355

356356
struct _zend_ast_ref {
357357
zend_refcounted_h gc;
358-
zend_ast *ast;
358+
/*zend_ast ast; zend_ast follows the zend_ast_ref structure */
359359
};
360360

361361
/* regular data types */
@@ -635,7 +635,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
635635
#define Z_AST(zval) (zval).value.ast
636636
#define Z_AST_P(zval_p) Z_AST(*(zval_p))
637637

638-
#define Z_ASTVAL(zval) (zval).value.ast->ast
638+
#define GC_AST(p) ((zend_ast*)(((char*)p) + sizeof(zend_ast_ref)))
639+
640+
#define Z_ASTVAL(zval) GC_AST(Z_AST(zval))
639641
#define Z_ASTVAL_P(zval_p) Z_ASTVAL(*(zval_p))
640642

641643
#define Z_INDIRECT(zval) (zval).value.zv
@@ -818,14 +820,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
818820
Z_TYPE_INFO_P(z) = IS_REFERENCE_EX; \
819821
} while (0)
820822

821-
#define ZVAL_NEW_AST(z, a) do { \
823+
#define ZVAL_AST(z, ast) do { \
822824
zval *__z = (z); \
823-
zend_ast_ref *_ast = \
824-
(zend_ast_ref *) emalloc(sizeof(zend_ast_ref)); \
825-
GC_REFCOUNT(_ast) = 1; \
826-
GC_TYPE_INFO(_ast) = IS_CONSTANT_AST; \
827-
_ast->ast = (a); \
828-
Z_AST_P(__z) = _ast; \
825+
Z_AST_P(__z) = ast; \
829826
Z_TYPE_INFO_P(__z) = IS_CONSTANT_AST_EX; \
830827
} while (0)
831828

Zend/zend_variables.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC
4646
case IS_CONSTANT_AST: {
4747
zend_ast_ref *ast = (zend_ast_ref*)p;
4848

49-
zend_ast_destroy_and_free(ast->ast);
50-
efree_size(ast, sizeof(zend_ast_ref));
49+
zend_ast_destroy(GC_AST(ast));
50+
efree(ast);
5151
break;
5252
}
5353
case IS_OBJECT: {
@@ -174,8 +174,7 @@ ZEND_API void ZEND_FASTCALL _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
174174
CHECK_ZVAL_STRING_REL(Z_STR_P(zvalue));
175175
Z_STR_P(zvalue) = zend_string_dup(Z_STR_P(zvalue), 0);
176176
} else if (EXPECTED(Z_TYPE_P(zvalue) == IS_CONSTANT_AST)) {
177-
zend_ast *copy = zend_ast_copy(Z_ASTVAL_P(zvalue));
178-
ZVAL_NEW_AST(zvalue, copy);
177+
ZVAL_AST(zvalue, zend_ast_copy(Z_ASTVAL_P(zvalue)));
179178
}
180179
}
181180

ext/opcache/zend_file_cache.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,7 @@ static void zend_file_cache_serialize_zval(zval *zv,
337337
SERIALIZE_PTR(Z_AST_P(zv));
338338
ast = Z_AST_P(zv);
339339
UNSERIALIZE_PTR(ast);
340-
if (!IS_SERIALIZED(ast->ast)) {
341-
ast->ast = zend_file_cache_serialize_ast(ast->ast, script, info, buf);
342-
}
340+
zend_file_cache_serialize_ast(Z_ASTVAL_P(zv), script, info, buf);
343341
}
344342
break;
345343
}
@@ -950,10 +948,7 @@ static void zend_file_cache_unserialize_zval(zval *zv,
950948
zend_ast_ref *ast;
951949

952950
UNSERIALIZE_PTR(Z_AST_P(zv));
953-
ast = Z_AST_P(zv);
954-
if (!IS_UNSERIALIZED(ast->ast)) {
955-
ast->ast = zend_file_cache_unserialize_ast(ast->ast, script, buf);
956-
}
951+
zend_file_cache_unserialize_ast(Z_ASTVAL_P(zv), script, buf);
957952
}
958953
break;
959954
}

ext/opcache/zend_persist.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
273273
}
274274
}
275275

276-
efree(ast);
277276
return node;
278277
}
279278

@@ -323,10 +322,12 @@ static void zend_persist_zval(zval *z)
323322
Z_AST_P(z) = new_ptr;
324323
Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_COPYABLE;
325324
} else {
326-
zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
327-
Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
325+
zend_ast_ref *old_ref = Z_AST_P(z);
326+
Z_ARR_P(z) = zend_accel_memdup(Z_AST_P(z), sizeof(zend_ast_ref));
327+
zend_persist_ast(GC_AST(old_ref));
328328
Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_COPYABLE;
329329
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
330+
efree(old_ref);
330331
}
331332
break;
332333
}

0 commit comments

Comments
 (0)