Skip to content

Commit 70f83f3

Browse files
committed
. The VM stacks for passing function arguments and syntaticaly nested calls were merged into a single stack. The stack size needed for op_array execution is calculated at compile time and preallocated at once. As result all the stack push operatins don't require checks for stack overflow any more.
. Generators implementation was improved using the new VM stack. Now it's a bit more clear and faster.
1 parent 9f7e53f commit 70f83f3

20 files changed

+1477
-1307
lines changed

Diff for: NEWS

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ PHP NEWS
33
?? ??? 201?, PHP 5.5.0
44

55
- General improvements:
6+
. The VM stacks for passing function arguments and syntaticaly nested calls
7+
were merged into a single stack. The stack size needed for op_array
8+
execution is calculated at compile time and preallocated at once. As result
9+
all the stack push operatins don't require checks for stack overflow
10+
any more. (Dmitry)
611
. Added support for generators. (Nikita Popov)
712
. Add simplified password hashing API
813
(https://wiki.php.net/rfc/password_hash). (Anthony Ferrara)

Diff for: UPGRADING

+21
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,27 @@ PHP 5.5 UPGRADE NOTES
2828
zend_logo_guid() have been removed
2929
- Removal of Logo GUIDs
3030

31+
- extensions can't override zend_execute() any more, they should override
32+
zend_execute_ex() instead. The EG(current_execute_data) is already
33+
initialized in zend_execute_ex(), so for compatibility extensions
34+
may need to use EG(current_execute_data)->prev_execute_data instead.
35+
- removed EG(arg_types_stack), EX(fbc), EX(called_scope), EX(current_object)
36+
- added op_array->nested_calls. It's calculated at compile time.
37+
- added EX(call_slots). It is an array to store information about syntaticaly
38+
nested calls (e.g. foo(bar())). It's preallocated together with execute_data.
39+
- added EX(call) - pointer to a current calling function. Actually an
40+
element of EX(call_slots)
41+
- opcodes INIT_METHOD_CALL, ZEND_INIT_STATIC_METHOD_CALL,
42+
ZEND_INIT_FCALL_BY_NAME, ZEND_INIT_NS_FCALL_BY_NAME use result.num as
43+
an index in EX(call_slots)
44+
- opcode ZEND_NEW uses extended_vallue as an index in EX(call_slots)
45+
- opcoes ZEND_DO_FCALL and ZEND_DO_FCALL_BY_NAME use op2.num as
46+
an index in EX(call_slots)
47+
- added op_array->used_stack. It's calculated at compile time and the
48+
corresponding stack space is preallocated together with execute_data.
49+
ZEND_SEND* and ZEND_DO_FCALL* don't need to check for stack overflow
50+
anymore.
51+
3152
========================================
3253
2. New Features
3354
========================================

Diff for: Zend/zend.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -683,11 +683,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS
683683
#if HAVE_DTRACE
684684
/* build with dtrace support */
685685
zend_compile_file = dtrace_compile_file;
686-
zend_execute = dtrace_execute;
686+
zend_execute_ex = dtrace_execute_ex;
687687
zend_execute_internal = dtrace_execute_internal;
688688
#else
689689
zend_compile_file = compile_file;
690-
zend_execute = execute;
690+
zend_execute_ex = execute_ex;
691691
zend_execute_internal = NULL;
692692
#endif /* HAVE_SYS_SDT_H */
693693
zend_compile_string = compile_string;

Diff for: Zend/zend_compile.c

+45-3
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
179179
CG(context).literals_size = 0;
180180
CG(context).current_brk_cont = -1;
181181
CG(context).backpatch_count = 0;
182+
CG(context).nested_calls = 0;
183+
CG(context).used_stack = 0;
182184
CG(context).labels = NULL;
183185
}
184186
/* }}} */
@@ -1950,6 +1952,9 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
19501952
function_name->u.constant.value.str.val = lcname;
19511953

19521954
zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
1955+
if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
1956+
CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
1957+
}
19531958
zend_do_extended_fcall_begin(TSRMLS_C);
19541959
return 0;
19551960
}
@@ -1988,11 +1993,13 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
19881993
GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
19891994
}
19901995
last_op->opcode = ZEND_INIT_METHOD_CALL;
1991-
SET_UNUSED(last_op->result);
1996+
last_op->result_type = IS_UNUSED;
1997+
last_op->result.num = CG(context).nested_calls;
19921998
Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
19931999
} else {
19942000
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
19952001
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2002+
opline->result.num = CG(context).nested_calls;
19962003
SET_UNUSED(opline->op1);
19972004
if (left_bracket->op_type == IS_CONST) {
19982005
opline->op2_type = IS_CONST;
@@ -2004,6 +2011,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
20042011
}
20052012

20062013
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2014+
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2015+
CG(active_op_array)->nested_calls = CG(context).nested_calls;
2016+
}
20072017
zend_do_extended_fcall_begin(TSRMLS_C);
20082018
}
20092019
/* }}} */
@@ -2031,12 +2041,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
20312041
/* In run-time PHP will check for function with full name and
20322042
internal function with short name */
20332043
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
2044+
opline->result.num = CG(context).nested_calls;
20342045
SET_UNUSED(opline->op1);
20352046
opline->op2_type = IS_CONST;
20362047
opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
20372048
GET_CACHE_SLOT(opline->op2.constant);
20382049
} else {
20392050
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2051+
opline->result.num = CG(context).nested_calls;
20402052
SET_UNUSED(opline->op1);
20412053
if (function_name->op_type == IS_CONST) {
20422054
opline->op2_type = IS_CONST;
@@ -2048,6 +2060,9 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
20482060
}
20492061

20502062
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2063+
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2064+
CG(active_op_array)->nested_calls = CG(context).nested_calls;
2065+
}
20512066
zend_do_extended_fcall_begin(TSRMLS_C);
20522067
}
20532068
/* }}} */
@@ -2395,6 +2410,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
23952410
opline->extended_value = class_node.EA ;
23962411
}
23972412
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
2413+
opline->result.num = CG(context).nested_calls;
23982414
if (class_node.op_type == IS_CONST) {
23992415
opline->op1_type = IS_CONST;
24002416
opline->op1.constant =
@@ -2416,6 +2432,9 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
24162432
}
24172433

24182434
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2435+
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2436+
CG(active_op_array)->nested_calls = CG(context).nested_calls;
2437+
}
24192438
zend_do_extended_fcall_begin(TSRMLS_C);
24202439
return 1; /* Dynamic */
24212440
}
@@ -2436,21 +2455,29 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
24362455
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
24372456
opline->opcode = ZEND_DO_FCALL;
24382457
SET_NODE(opline->op1, function_name);
2458+
SET_UNUSED(opline->op2);
2459+
opline->op2.num = CG(context).nested_calls;
24392460
CALCULATE_LITERAL_HASH(opline->op1.constant);
24402461
GET_CACHE_SLOT(opline->op1.constant);
24412462
} else {
24422463
opline->opcode = ZEND_DO_FCALL_BY_NAME;
24432464
SET_UNUSED(opline->op1);
2465+
SET_UNUSED(opline->op2);
2466+
opline->op2.num = --CG(context).nested_calls;
24442467
}
24452468
}
24462469

24472470
opline->result.var = get_temporary_variable(CG(active_op_array));
24482471
opline->result_type = IS_VAR;
2449-
GET_NODE(result, opline->result) ;
2450-
SET_UNUSED(opline->op2);
2472+
GET_NODE(result, opline->result);
24512473

24522474
zend_stack_del_top(&CG(function_call_stack));
24532475
opline->extended_value = Z_LVAL(argument_list->u.constant);
2476+
2477+
if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
2478+
CG(active_op_array)->used_stack = CG(context).used_stack + 1;
2479+
}
2480+
CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
24542481
}
24552482
/* }}} */
24562483

@@ -2558,6 +2585,10 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
25582585
SET_NODE(opline->op1, param);
25592586
opline->op2.opline_num = offset;
25602587
SET_UNUSED(opline->op2);
2588+
2589+
if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
2590+
CG(active_op_array)->used_stack = CG(context).used_stack;
2591+
}
25612592
}
25622593
/* }}} */
25632594

@@ -5547,12 +5578,16 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /*
55475578
new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
55485579
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
55495580
opline->opcode = ZEND_NEW;
5581+
opline->extended_value = CG(context).nested_calls;
55505582
opline->result_type = IS_VAR;
55515583
opline->result.var = get_temporary_variable(CG(active_op_array));
55525584
SET_NODE(opline->op1, class_type);
55535585
SET_UNUSED(opline->op2);
55545586

55555587
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
5588+
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
5589+
CG(active_op_array)->nested_calls = CG(context).nested_calls;
5590+
}
55565591
}
55575592
/* }}} */
55585593

@@ -5765,6 +5800,13 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
57655800
opline->extended_value = 1;
57665801
SET_UNUSED(opline->op2);
57675802
GET_NODE(result, opline->result);
5803+
5804+
if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
5805+
CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
5806+
}
5807+
if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) {
5808+
CG(active_op_array)->used_stack = CG(context).used_stack + 2;
5809+
}
57685810
}
57695811
/* }}} */
57705812

Diff for: Zend/zend_compile.h

+15-3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ typedef struct _zend_compiler_context {
5959
int literals_size;
6060
int current_brk_cont;
6161
int backpatch_count;
62+
int nested_calls;
63+
int used_stack;
6264
HashTable *labels;
6365
} zend_compiler_context;
6466

@@ -279,6 +281,9 @@ struct _zend_op_array {
279281

280282
zend_uint T;
281283

284+
zend_uint nested_calls;
285+
zend_uint used_stack;
286+
282287
zend_brk_cont_element *brk_cont_array;
283288
int last_brk_cont;
284289

@@ -369,11 +374,17 @@ typedef struct _list_llist_element {
369374

370375
union _temp_variable;
371376

377+
typedef struct _call_slot {
378+
zend_function *fbc;
379+
zval *object;
380+
zend_class_entry *called_scope;
381+
zend_bool is_ctor_call;
382+
zend_bool is_ctor_result_used;
383+
} call_slot;
384+
372385
struct _zend_execute_data {
373386
struct _zend_op *opline;
374387
zend_function_state function_state;
375-
zend_function *fbc; /* Function Being Called */
376-
zend_class_entry *called_scope;
377388
zend_op_array *op_array;
378389
zval *object;
379390
union _temp_variable *Ts;
@@ -386,8 +397,9 @@ struct _zend_execute_data {
386397
zend_class_entry *current_scope;
387398
zend_class_entry *current_called_scope;
388399
zval *current_this;
389-
zval *current_object;
390400
struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
401+
call_slot *call_slots;
402+
call_slot *call;
391403
};
392404

393405
#define EX(element) execute_data.element

Diff for: Zend/zend_execute.c

-19
Original file line numberDiff line numberDiff line change
@@ -1570,25 +1570,6 @@ void zend_free_compiled_variables(zval ***CVs, int num) /* {{{ */
15701570
}
15711571
/* }}} */
15721572

1573-
void** zend_copy_arguments(void **arguments_end) /* {{{ */
1574-
{
1575-
int arguments_count = (int) (zend_uintptr_t) *arguments_end;
1576-
size_t arguments_size = (arguments_count + 1) * sizeof(void **);
1577-
void **arguments_start = arguments_end - arguments_count;
1578-
void **copied_arguments_start = emalloc(arguments_size);
1579-
void **copied_arguments_end = copied_arguments_start + arguments_count;
1580-
int i;
1581-
1582-
memcpy(copied_arguments_start, arguments_start, arguments_size);
1583-
1584-
for (i = 0; i < arguments_count; i++) {
1585-
Z_ADDREF_P((zval *) arguments_start[i]);
1586-
}
1587-
1588-
return copied_arguments_end;
1589-
}
1590-
/* }}} */
1591-
15921573
/*
15931574
* Local variables:
15941575
* tab-width: 4

0 commit comments

Comments
 (0)