Skip to content

Commit f2df6a4

Browse files
committed
- Improved memory usage
. zend_function.pass_rest_by_reference is replaced by ZEND_ACC_PASS_REST_BY_REFERENCE in zend_function.fn_flags . zend_function.return_reference is replaced by ZEND_ACC_RETURN_REFERENCE in zend_function.fn_flags . zend_arg_info.required_num_args removed. it was needed only for internal functions. Now the first arg_info for internal function (which has special meaning) is represented by zend_internal_function_info structure. . zend_op_array.size, size_var, size_literal, current_brk_cont, backpatch_count moved into CG(context), because they are used only during compilation. . zend_op_array.start_op is moved into EG(start_op), because it's used only for 'interactive' execution of single top-level op-array. . zend_op_array.done_pass_two is replaced by ZEND_ACC_DONE_PASS_TWO in zend_op_array.fn_flags. . op_array.vars array is trimmed (reallocated) during pass_two. . zend_class_entry.constants_updated is replaced by ZEND_ACC_CONSTANTS_UPDATED in zend_class_entry.ce_flags . the size of zend_class_entry is reduced by sharing the same memory space by different information for internal and user classes. See zend_class_inttry.info union.
1 parent 3e92b20 commit f2df6a4

20 files changed

+359
-278
lines changed

NEWS

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@
6868
- Changed session.entropy_file to default to /dev/urandom or /dev/arandom if
6969
either is present at compile time. (Rasmus)
7070

71+
- Improved memory usage (Dmitry)
72+
. zend_function.pass_rest_by_reference is replaced by
73+
ZEND_ACC_PASS_REST_BY_REFERENCE in zend_function.fn_flags
74+
. zend_function.return_reference is replaced by ZEND_ACC_RETURN_REFERENCE
75+
in zend_function.fn_flags
76+
. zend_arg_info.required_num_args removed. it was needed only for internal
77+
functions. Now the first arg_info for internal function (which has special
78+
meaning) is represented by zend_internal_function_info structure.
79+
. zend_op_array.size, size_var, size_literal, current_brk_cont,
80+
backpatch_count moved into CG(context), because they are used only during
81+
compilation.
82+
. zend_op_array.start_op is moved into EG(start_op), because it's used
83+
only for 'interactive' execution of single top-level op-array.
84+
. zend_op_array.done_pass_two is replaced by ZEND_ACC_DONE_PASS_TWO in
85+
zend_op_array.fn_flags.
86+
. op_array.vars array is trimmed (reallocated) during pass_two.
87+
. zend_class_entry.constants_updated is replaced by
88+
ZEND_ACC_CONSTANTS_UPDATED in zend_class_entry.ce_flags
89+
. the size of zend_class_entry is reduced by sharing the same memory space
90+
by different information for internal and user classes.
91+
See zend_class_inttry.info union.
7192
- Improved CLI Interactive readline shell (Johannes)
7293
. Added cli.pager ini setting to set a pager for output.
7394
. Added cli.prompt ini settingto configure the shell prompt.

UPGRADING.INTERNALS

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,32 @@ php_sys_lstat is an alias to lstat (when avaible). On Windows it is now
2121
available using php_sys_lstat. php_sys_stat and php_sys_lstat usage is recommended
2222
instead of calling lstat directly, to ensure portability.
2323

24-
b. readlink support
24+
c. readlink support
2525

2626
readlink is now available on all platforms. On unix-like platform
2727
php_sys_readlink is an alias to readlink (when avaible). On Windows it is now
2828
available using php_sys_readlink. php_sys_readlink usage is recommended
2929
instead of calling readlink directly, to ensure portability.
30+
31+
d. layout of some core ZE structures (zend_op_array, zend_class_entry, ...)
32+
33+
. zend_function.pass_rest_by_reference is replaced by
34+
ZEND_ACC_PASS_REST_BY_REFERENCE in zend_function.fn_flags
35+
. zend_function.return_reference is replaced by ZEND_ACC_RETURN_REFERENCE
36+
in zend_function.fn_flags
37+
. zend_arg_info.required_num_args removed. it was needed only for internal
38+
functions. Now the first arg_info for internal function (which has special
39+
meaning) is represented by zend_internal_function_info structure.
40+
. zend_op_array.size, size_var, size_literal, current_brk_cont,
41+
backpatch_count moved into CG(context), because they are used only during
42+
compilation.
43+
. zend_op_array.start_op is moved into EG(start_op), because it's used
44+
only for 'interactive' execution of single top-level op-array.
45+
. zend_op_array.done_pass_two is replaced by ZEND_ACC_DONE_PASS_TWO in
46+
zend_op_array.fn_flags.
47+
. op_array.vars array is trimmed (reallocated) during pass_two.
48+
. zend_class_entry.constants_updated is replaced by
49+
ZEND_ACC_CONSTANTS_UPDATED in zend_class_entry.ce_flags
50+
. the size of zend_class_entry is reduced by sharing the same memory space
51+
by different information for internal and user classes.
52+
See zend_class_inttry.info union.

Zend/zend.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,6 @@ struct _zend_class_entry {
465465
zend_uint name_length;
466466
struct _zend_class_entry *parent;
467467
int refcount;
468-
zend_bool constants_updated;
469468
zend_uint ce_flags;
470469

471470
HashTable function_table;
@@ -476,7 +475,6 @@ struct _zend_class_entry {
476475
HashTable constants_table;
477476
int default_properties_count;
478477
int default_static_members_count;
479-
const struct _zend_function_entry *builtin_functions;
480478

481479
union _zend_function *constructor;
482480
union _zend_function *destructor;
@@ -511,13 +509,19 @@ struct _zend_class_entry {
511509
zend_trait_alias **trait_aliases;
512510
zend_trait_precedence **trait_precedences;
513511

514-
char *filename;
515-
zend_uint line_start;
516-
zend_uint line_end;
517-
char *doc_comment;
518-
zend_uint doc_comment_len;
519-
520-
struct _zend_module_entry *module;
512+
union {
513+
struct {
514+
char *filename;
515+
zend_uint line_start;
516+
zend_uint line_end;
517+
char *doc_comment;
518+
zend_uint doc_comment_len;
519+
} user;
520+
struct {
521+
const struct _zend_function_entry *builtin_functions;
522+
struct _zend_module_entry *module;
523+
} internal;
524+
} info;
521525
};
522526

523527
#include "zend_stream.h"

Zend/zend_API.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro
10151015

10161016
ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
10171017
{
1018-
if (!class_type->constants_updated || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) {
1018+
if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0 || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) {
10191019
zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry);
10201020
zend_class_entry *old_scope = *scope;
10211021
int i;
@@ -1070,7 +1070,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC
10701070
}
10711071

10721072
*scope = old_scope;
1073-
class_type->constants_updated = 1;
1073+
class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
10741074
}
10751075
}
10761076
/* }}} */
@@ -1953,24 +1953,6 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
19531953
internal_function->function_name = (char*)ptr->fname;
19541954
internal_function->scope = scope;
19551955
internal_function->prototype = NULL;
1956-
if (ptr->arg_info) {
1957-
internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
1958-
internal_function->num_args = ptr->num_args;
1959-
/* Currently you cannot denote that the function can accept less arguments than num_args */
1960-
if (ptr->arg_info[0].required_num_args == -1) {
1961-
internal_function->required_num_args = ptr->num_args;
1962-
} else {
1963-
internal_function->required_num_args = ptr->arg_info[0].required_num_args;
1964-
}
1965-
internal_function->pass_rest_by_reference = ptr->arg_info[0].pass_by_reference;
1966-
internal_function->return_reference = ptr->arg_info[0].return_reference;
1967-
} else {
1968-
internal_function->arg_info = NULL;
1969-
internal_function->num_args = 0;
1970-
internal_function->required_num_args = 0;
1971-
internal_function->pass_rest_by_reference = 0;
1972-
internal_function->return_reference = 0;
1973-
}
19741956
if (ptr->flags) {
19751957
if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
19761958
if (ptr->flags != ZEND_ACC_DEPRECATED || scope) {
@@ -1983,6 +1965,32 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
19831965
} else {
19841966
internal_function->fn_flags = ZEND_ACC_PUBLIC;
19851967
}
1968+
if (ptr->arg_info) {
1969+
zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
1970+
1971+
internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
1972+
internal_function->num_args = ptr->num_args;
1973+
/* Currently you cannot denote that the function can accept less arguments than num_args */
1974+
if (info->required_num_args == -1) {
1975+
internal_function->required_num_args = ptr->num_args;
1976+
} else {
1977+
internal_function->required_num_args = info->required_num_args;
1978+
}
1979+
if (info->pass_rest_by_reference) {
1980+
if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) {
1981+
internal_function->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF;
1982+
} else {
1983+
internal_function->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE;
1984+
}
1985+
}
1986+
if (info->return_reference) {
1987+
internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1988+
}
1989+
} else {
1990+
internal_function->arg_info = NULL;
1991+
internal_function->num_args = 0;
1992+
internal_function->required_num_args = 0;
1993+
}
19861994
if (ptr->flags & ZEND_ACC_ABSTRACT) {
19871995
if (scope) {
19881996
/* This is a class that must be abstract itself. Here we set the check info. */
@@ -2353,10 +2361,10 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class
23532361
class_entry->type = ZEND_INTERNAL_CLASS;
23542362
zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
23552363
class_entry->ce_flags = ce_flags;
2356-
class_entry->module = EG(current_module);
2364+
class_entry->info.internal.module = EG(current_module);
23572365

2358-
if (class_entry->builtin_functions) {
2359-
zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
2366+
if (class_entry->info.internal.builtin_functions) {
2367+
zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
23602368
}
23612369

23622370
zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
@@ -2712,15 +2720,13 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
27122720
if (strict_class && ce_org->__call) {
27132721
fcc->function_handler = emalloc(sizeof(zend_internal_function));
27142722
fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
2715-
fcc->function_handler->internal_function.module = ce_org->module;
2723+
fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL;
27162724
fcc->function_handler->internal_function.handler = zend_std_call_user_call;
27172725
fcc->function_handler->internal_function.arg_info = NULL;
27182726
fcc->function_handler->internal_function.num_args = 0;
27192727
fcc->function_handler->internal_function.scope = ce_org;
27202728
fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
27212729
fcc->function_handler->internal_function.function_name = estrndup(mname, mlen);
2722-
fcc->function_handler->internal_function.pass_rest_by_reference = 0;
2723-
fcc->function_handler->internal_function.return_reference = ZEND_RETURN_VALUE;
27242730
call_via_handler = 1;
27252731
retval = 1;
27262732
} else if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) {

Zend/zend_API.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,14 @@ typedef struct _zend_fcall_info_cache {
9696
#define ZEND_NS_FALIAS(ns, name, alias, arg_info) ZEND_NS_FENTRY(ns, name, ZEND_FN(alias), arg_info, 0)
9797
#define ZEND_NS_DEP_FALIAS(ns, name, alias, arg_info) ZEND_NS_FENTRY(ns, name, ZEND_FN(alias), arg_info, ZEND_ACC_DEPRECATED)
9898

99-
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
100-
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
101-
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_CLASS, allow_null, pass_by_ref, 0, 0 },
102-
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref, 0, 0 },
103-
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref, 0, 0 },
99+
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref},
100+
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref},
101+
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_CLASS, allow_null, pass_by_ref},
102+
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref},
103+
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref},
104104
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
105105
static const zend_arg_info name[] = { \
106-
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
106+
{ NULL, 0, NULL, required_num_args, 0, return_reference, pass_rest_by_reference},
107107
#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) \
108108
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1)
109109
#define ZEND_END_ARG_INFO() };
@@ -173,7 +173,6 @@ typedef struct _zend_fcall_info_cache {
173173
class_container.name = zend_strndup(cl_name, _len); \
174174
} \
175175
class_container.name_length = _len; \
176-
class_container.builtin_functions = functions; \
177176
class_container.constructor = NULL; \
178177
class_container.destructor = NULL; \
179178
class_container.clone = NULL; \
@@ -202,7 +201,8 @@ typedef struct _zend_fcall_info_cache {
202201
class_container.interfaces = NULL; \
203202
class_container.get_iterator = NULL; \
204203
class_container.iterator_funcs.funcs = NULL; \
205-
class_container.module = NULL; \
204+
class_container.info.internal.module = NULL; \
205+
class_container.info.internal.builtin_functions = functions; \
206206
}
207207

208208
#define INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, handle_fcall, handle_propget, handle_propset) \

Zend/zend_closures.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {
129129

130130
invoke->common = closure->func.common;
131131
invoke->type = ZEND_INTERNAL_FUNCTION;
132-
invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
132+
invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE);
133133
invoke->internal_function.handler = ZEND_MN(Closure___invoke);
134134
invoke->internal_function.module = 0;
135135
invoke->internal_function.scope = zend_ce_closure;

0 commit comments

Comments
 (0)