Skip to content

Commit c1965f5

Browse files
committed
Use reference counting instead of zval duplication
1 parent 3d87391 commit c1965f5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+915
-878
lines changed

Zend/zend.h

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,13 @@ END_EXTERN_C()
707707
} \
708708
} while (0)
709709

710+
#define ZVAL_MAKE_REF(zv) do { \
711+
zval *__zv = (zv); \
712+
if (!Z_ISREF_P(__zv)) { \
713+
ZVAL_NEW_REF(__zv, __zv); \
714+
} \
715+
} while (0)
716+
710717
#define ZVAL_UNREF(z) do { \
711718
zval *_z = (z); \
712719
zend_reference *ref; \
@@ -716,6 +723,38 @@ END_EXTERN_C()
716723
efree(ref); \
717724
} while (0)
718725

726+
#define SEPARATE_STRING(zv) do { \
727+
zval *_zv = (zv); \
728+
if (Z_REFCOUNTED_P(_zv) && \
729+
Z_REFCOUNT_P(_zv) > 1) { \
730+
Z_DELREF_P(_zv); \
731+
zval_copy_ctor_func(_zv); \
732+
} \
733+
} while (0)
734+
735+
#define SEPARATE_ARRAY(zv) do { \
736+
zval *_zv = (zv); \
737+
if (Z_IMMUTABLE_P(_zv)) { \
738+
zval_copy_ctor_func(_zv); \
739+
} else if (Z_REFCOUNT_P(_zv) > 1) { \
740+
Z_DELREF_P(_zv); \
741+
zval_copy_ctor_func(_zv); \
742+
} \
743+
} while (0)
744+
745+
#define SEPARATE_ZVAL_NOREF(zv) do { \
746+
zval *_zv = (zv); \
747+
if (Z_COPYABLE_P(_zv) || \
748+
Z_IMMUTABLE_P(_zv)) { \
749+
if (Z_IMMUTABLE_P(_zv)) { \
750+
zval_copy_ctor_func(_zv); \
751+
} else if (Z_REFCOUNT_P(_zv) > 1) { \
752+
Z_DELREF_P(_zv); \
753+
zval_copy_ctor_func(_zv); \
754+
} \
755+
} \
756+
} while (0)
757+
719758
#define SEPARATE_ZVAL(zv) do { \
720759
zval *_zv = (zv); \
721760
if (Z_REFCOUNTED_P(_zv) || \
@@ -749,38 +788,10 @@ END_EXTERN_C()
749788
} \
750789
} while (0)
751790

752-
#define SEPARATE_ZVAL_IF_REF(zv) do { \
753-
zval *__zv = (zv); \
754-
if (Z_ISREF_P(__zv)) { \
755-
if (Z_REFCOUNT_P(__zv) == 1) { \
756-
ZVAL_UNREF(__zv); \
757-
} else { \
758-
Z_DELREF_P(__zv); \
759-
ZVAL_DUP(__zv, Z_REFVAL_P(__zv)); \
760-
} \
761-
} \
762-
} while (0)
763-
764-
#define SEPARATE_ZVAL_TO_MAKE_IS_REF(zv) do { \
765-
zval *__zv = (zv); \
766-
if (!Z_ISREF_P(__zv)) { \
767-
if (Z_COPYABLE_P(__zv) && \
768-
Z_REFCOUNT_P(__zv) > 1) { \
769-
Z_DELREF_P(__zv); \
770-
zval_copy_ctor_func(__zv); \
771-
} \
772-
ZVAL_NEW_REF(__zv, __zv); \
773-
} \
774-
} while (0)
775-
776791
#define SEPARATE_ARG_IF_REF(varptr) do { \
777-
zval *_varptr = (varptr); \
778-
if (Z_ISREF_P(_varptr)) { \
779-
zval tmp; \
780-
ZVAL_DUP(&tmp, Z_REFVAL_P(_varptr)); \
781-
varptr = &tmp; \
782-
} else if (Z_REFCOUNTED_P(_varptr)) { \
783-
Z_ADDREF_P(_varptr); \
792+
ZVAL_DEREF(varptr); \
793+
if (Z_REFCOUNTED_P(varptr)) { \
794+
Z_ADDREF_P(varptr); \
784795
} \
785796
} while (0)
786797

Zend/zend_API.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static int parse_arg_object_to_string(zval *arg, char **p, int *pl, int type TSR
273273
}
274274
/* Standard PHP objects */
275275
if (Z_OBJ_HT_P(arg) == &std_object_handlers || !Z_OBJ_HANDLER_P(arg, cast_object)) {
276-
SEPARATE_ZVAL_IF_NOT_REF(arg);
276+
SEPARATE_ZVAL_NOREF(arg);
277277
if (zend_std_cast_object_tostring(arg, arg, type TSRMLS_CC) == SUCCESS) {
278278
*pl = Z_STRLEN_P(arg);
279279
*p = Z_STRVAL_P(arg);
@@ -315,7 +315,7 @@ static int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS
315315
}
316316
/* Standard PHP objects */
317317
if (Z_OBJ_HT_P(arg) == &std_object_handlers || !Z_OBJ_HANDLER_P(arg, cast_object)) {
318-
SEPARATE_ZVAL_IF_NOT_REF(arg);
318+
SEPARATE_ZVAL_NOREF(arg);
319319
if (zend_std_cast_object_tostring(arg, arg, type TSRMLS_CC) == SUCCESS) {
320320
*str = Z_STR_P(arg);
321321
return SUCCESS;
@@ -350,9 +350,11 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
350350
zval *real_arg = arg;
351351

352352
/* scan through modifiers */
353+
ZVAL_DEREF(arg);
353354
while (1) {
354355
if (*spec_walk == '/') {
355-
SEPARATE_ZVAL_IF_NOT_REF(arg);
356+
SEPARATE_ZVAL(arg);
357+
real_arg = arg;
356358
} else if (*spec_walk == '!') {
357359
check_null = 1;
358360
} else {
@@ -361,8 +363,6 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
361363
spec_walk++;
362364
}
363365

364-
ZVAL_DEREF(arg);
365-
366366
switch (c) {
367367
case 'l':
368368
case 'L':
@@ -486,12 +486,6 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
486486
case IS_TRUE:
487487
convert_to_string_ex(arg);
488488
case IS_STRING:
489-
if (UNEXPECTED(Z_ISREF_P(arg))) {
490-
/* it's dangerous to return pointers to string
491-
buffer of referenced variable, because it can
492-
be clobbered throug magic callbacks */
493-
SEPARATE_ZVAL(arg);
494-
}
495489
*p = Z_STRVAL_P(arg);
496490
*pl = Z_STRLEN_P(arg);
497491
if (c == 'p' && CHECK_ZVAL_NULL_PATH(arg)) {
@@ -533,12 +527,6 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
533527
case IS_TRUE:
534528
convert_to_string_ex(arg);
535529
case IS_STRING:
536-
if (UNEXPECTED(Z_ISREF_P(arg))) {
537-
/* it's dangerous to return pointers to string
538-
buffer of referenced variable, because it can
539-
be clobbered throug magic callbacks */
540-
SEPARATE_ZVAL(arg);
541-
}
542530
*str = Z_STR_P(arg);
543531
if (c == 'P' && CHECK_ZVAL_NULL_PATH(arg)) {
544532
return "a valid path";
@@ -2714,8 +2702,8 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_lengt
27142702

27152703
if (num_symbol_tables <= 0) return FAILURE;
27162704

2717-
if (is_ref && !Z_ISREF_P(symbol)) {
2718-
ZVAL_NEW_REF(symbol, symbol);
2705+
if (is_ref) {
2706+
ZVAL_MAKE_REF(symbol);
27192707
}
27202708

27212709
va_start(symbol_table_list, num_symbol_tables);

Zend/zend_builtin_functions.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,11 +585,10 @@ ZEND_FUNCTION(each)
585585
HashTable *target_hash;
586586
zend_string *key;
587587

588-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &array) == FAILURE) {
588+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &array) == FAILURE) {
589589
return;
590590
}
591591

592-
ZVAL_DEREF(array);
593592
target_hash = HASH_OF(array);
594593
if (!target_hash) {
595594
zend_error(E_WARNING,"Variable passed to each() is not an array or object");

Zend/zend_compile.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,7 +3793,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
37933793
}
37943794
}
37953795
for (i = 0; i < parent_ce->default_static_members_count; i++) {
3796-
SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
3796+
ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
37973797
ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
37983798
Z_ADDREF(ce->default_static_members_table[i]);
37993799
}
@@ -3811,7 +3811,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
38113811
}
38123812
}
38133813
for (i = 0; i < parent_ce->default_static_members_count; i++) {
3814-
SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]);
3814+
ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
38153815
ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
38163816
Z_ADDREF(ce->default_static_members_table[i]);
38173817
}
@@ -3896,9 +3896,7 @@ static int do_inherit_iface_constant(zval *zv TSRMLS_DC, int num_args, va_list a
38963896
zend_class_entry *iface = va_arg(args, zend_class_entry *);
38973897

38983898
if (hash_key->key && do_inherit_constant_check(&ce->constants_table, zv, hash_key, iface)) {
3899-
if (!Z_ISREF_P(zv)) {
3900-
ZVAL_NEW_REF(zv, zv);
3901-
}
3899+
ZVAL_MAKE_REF(zv);
39023900
Z_ADDREF_P(zv);
39033901
zend_hash_update(&ce->constants_table, hash_key->key, zv);
39043902
}
@@ -7524,6 +7522,9 @@ void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC) /* {{{
75247522
if (ast->kind == ZEND_CONST) {
75257523
ZVAL_COPY_VALUE(&result->u.constant, &ast->u.val);
75267524
efree(ast);
7525+
if (Z_TYPE(result->u.constant) == IS_ARRAY) {
7526+
zend_make_immutable_array_r(&result->u.constant TSRMLS_CC);
7527+
}
75277528
} else if (zend_ast_is_ct_constant(ast)) {
75287529
zend_ast_evaluate(&result->u.constant, ast, NULL TSRMLS_CC);
75297530
zend_ast_destroy(ast);

0 commit comments

Comments
 (0)