Skip to content

Commit baf97b1

Browse files
committed
We don't nees zend_op_array->brk_cont_array at run-time anymore.
Move zend_op_array->brk_cont_array into CG(context).brk_cont_array. Use more compact zend_op_array->live_range instead of zend_op_array->brk_cont_array. Semantic is kept unchanged.
1 parent 71092b7 commit baf97b1

12 files changed

+186
-148
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Optimization of constant switch expression
3+
--FILE--
4+
<?php
5+
try {
6+
switch ("1" . (int)2) {
7+
case 12:
8+
throw new Exception();
9+
}
10+
} catch (Exception $e) {
11+
echo "exception\n";
12+
}
13+
?>
14+
--EXPECT--
15+
exception

Zend/zend_compile.c

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,22 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
218218
CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
219219
CG(context).vars_size = 0;
220220
CG(context).literals_size = 0;
221-
CG(context).current_brk_cont = -1;
222221
CG(context).backpatch_count = 0;
223222
CG(context).in_finally = 0;
224223
CG(context).fast_call_var = -1;
224+
CG(context).current_brk_cont = -1;
225+
CG(context).last_brk_cont = 0;
226+
CG(context).brk_cont_array = NULL;
225227
CG(context).labels = NULL;
226228
}
227229
/* }}} */
228230

229231
void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */
230232
{
233+
if (CG(context).brk_cont_array) {
234+
efree(CG(context).brk_cont_array);
235+
CG(context).brk_cont_array = NULL;
236+
}
231237
if (CG(context).labels) {
232238
zend_hash_destroy(CG(context).labels);
233239
FREE_HASHTABLE(CG(context).labels);
@@ -567,14 +573,28 @@ void zend_stop_lexing(void)
567573
LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
568574
}
569575

576+
static void zend_add_live_range(zend_op_array *op_array, uint32_t start, uint32_t end) /* {{{ */
577+
{
578+
zend_live_range *range;
579+
580+
if (start != end) {
581+
op_array->last_live_range++;
582+
op_array->live_range = erealloc(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
583+
range = op_array->live_range + op_array->last_live_range - 1;
584+
range->start = start;
585+
range->end = end;
586+
}
587+
}
588+
/* }}} */
589+
570590
static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var) /* {{{ */
571591
{
572592
zend_brk_cont_element *brk_cont_element;
573593
int parent = CG(context).current_brk_cont;
574594
zend_loop_var info = {0};
575595

576-
CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont;
577-
brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
596+
CG(context).current_brk_cont = CG(context).last_brk_cont;
597+
brk_cont_element = get_next_brk_cont_element();
578598
brk_cont_element->parent = parent;
579599

580600
if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) {
@@ -597,7 +617,7 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var
597617
static inline void zend_end_loop(int cont_addr) /* {{{ */
598618
{
599619
zend_brk_cont_element *brk_cont_element
600-
= &CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont];
620+
= &CG(context).brk_cont_array[CG(context).current_brk_cont];
601621
brk_cont_element->cont = cont_addr;
602622
brk_cont_element->brk = get_next_op_number(CG(active_op_array));
603623
CG(context).current_brk_cont = brk_cont_element->parent;
@@ -3734,14 +3754,14 @@ void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{{ */
37343754
ZVAL_NULL(label);
37353755

37363756
current = opline->extended_value;
3737-
for (; current != dest->brk_cont; current = op_array->brk_cont_array[current].parent) {
3757+
for (; current != dest->brk_cont; current = CG(context).brk_cont_array[current].parent) {
37383758
if (current == -1) {
37393759
CG(in_compilation) = 1;
37403760
CG(active_op_array) = op_array;
37413761
CG(zend_lineno) = opline->lineno;
37423762
zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
37433763
}
3744-
if (op_array->brk_cont_array[current].start >= 0) {
3764+
if (CG(context).brk_cont_array[current].start >= 0) {
37453765
remove_oplines--;
37463766
}
37473767
}
@@ -3989,7 +4009,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
39894009

39904010
zend_end_loop(opnum_fetch);
39914011

3992-
zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL);
4012+
opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL);
4013+
zend_add_live_range(CG(active_op_array),
4014+
opnum_fetch, opline - CG(active_op_array)->opcodes);
39934015
}
39944016
/* }}} */
39954017

@@ -4046,10 +4068,11 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
40464068
znode expr_node, case_node;
40474069
zend_op *opline;
40484070
uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
4049-
uint32_t opnum_default_jmp;
4071+
uint32_t opnum_default_jmp, opnum_start;
40504072

40514073
zend_compile_expr(&expr_node, expr_ast);
40524074

4075+
opnum_start = get_next_op_number(CG(active_op_array));
40534076
zend_begin_loop(ZEND_FREE, &expr_node);
40544077

40554078
case_node.op_type = IS_TMP_VAR;
@@ -4112,7 +4135,9 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
41124135
zend_end_loop(get_next_op_number(CG(active_op_array)));
41134136

41144137
if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) {
4115-
zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
4138+
opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
4139+
zend_add_live_range(CG(active_op_array),
4140+
opnum_start, opline - CG(active_op_array)->opcodes);
41164141
} else if (expr_node.op_type == IS_CONST) {
41174142
zval_dtor(&expr_node.u.constant);
41184143
}
@@ -6426,8 +6451,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
64266451
{
64276452
zend_ast *expr_ast = ast->child[0];
64286453
znode silence_node;
6429-
uint32_t begin_opline_num, end_opline_num;
6430-
zend_brk_cont_element *brk_cont_element;
6454+
uint32_t begin_opline_num;
6455+
zend_op *opline;
64316456

64326457
begin_opline_num = get_next_op_number(CG(active_op_array));
64336458
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
@@ -6440,15 +6465,12 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
64406465
zend_compile_expr(result, expr_ast);
64416466
}
64426467

6443-
end_opline_num = get_next_op_number(CG(active_op_array));
6444-
zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
6468+
opline = zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
64456469

64466470
/* Store BEGIN_SILENCE/END_SILENCE pair to restore previous
64476471
* EG(error_reporting) value on exception */
6448-
brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
6449-
brk_cont_element->start = begin_opline_num;
6450-
brk_cont_element->cont = brk_cont_element->brk = end_opline_num;
6451-
brk_cont_element->parent = -1;
6472+
zend_add_live_range(CG(active_op_array),
6473+
begin_opline_num + 1, opline - CG(active_op_array)->opcodes);
64526474
}
64536475
/* }}} */
64546476

@@ -6768,10 +6790,6 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
67686790
GET_NODE(result, opline->result);
67696791
} else {
67706792
uint32_t var;
6771-
zend_brk_cont_element *info = get_next_brk_cont_element(CG(active_op_array));
6772-
info->start = rope_init_lineno;
6773-
info->parent = CG(context).current_brk_cont;
6774-
info->cont = info->brk = opline - CG(active_op_array)->opcodes;
67756793

67766794
init_opline->extended_value = j;
67776795
opline->opcode = ZEND_ROPE_END;
@@ -6785,6 +6803,10 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
67856803
get_temporary_variable(CG(active_op_array));
67866804
i--;
67876805
}
6806+
6807+
zend_add_live_range(CG(active_op_array),
6808+
rope_init_lineno, opline - CG(active_op_array)->opcodes);
6809+
67886810
/* Update all the previous opcodes to use the same variable */
67896811
while (opline != init_opline) {
67906812
opline--;

Zend/zend_compile.h

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,6 @@ typedef struct _zend_declarables {
111111
zend_long ticks;
112112
} zend_declarables;
113113

114-
/* Compilation context that is different for each op array. */
115-
typedef struct _zend_oparray_context {
116-
uint32_t opcodes_size;
117-
int vars_size;
118-
int literals_size;
119-
int current_brk_cont;
120-
int backpatch_count;
121-
int in_finally;
122-
uint32_t fast_call_var;
123-
HashTable *labels;
124-
} zend_oparray_context;
125-
126114
/* Compilation context that is different for each file, but shared between op arrays. */
127115
typedef struct _zend_file_context {
128116
zend_declarables declarables;
@@ -185,6 +173,25 @@ typedef struct _zend_try_catch_element {
185173
uint32_t finally_end;
186174
} zend_try_catch_element;
187175

176+
typedef struct _zend_live_range {
177+
uint32_t start;
178+
uint32_t end;
179+
} zend_live_range;
180+
181+
/* Compilation context that is different for each op array. */
182+
typedef struct _zend_oparray_context {
183+
uint32_t opcodes_size;
184+
int vars_size;
185+
int literals_size;
186+
int backpatch_count;
187+
int in_finally;
188+
uint32_t fast_call_var;
189+
int current_brk_cont;
190+
int last_brk_cont;
191+
zend_brk_cont_element *brk_cont_array;
192+
HashTable *labels;
193+
} zend_oparray_context;
194+
188195
/* method flags (types) */
189196
#define ZEND_ACC_STATIC 0x01
190197
#define ZEND_ACC_ABSTRACT 0x02
@@ -354,9 +361,9 @@ struct _zend_op_array {
354361
uint32_t T;
355362
zend_string **vars;
356363

357-
int last_brk_cont;
364+
int last_live_range;
358365
int last_try_catch;
359-
zend_brk_cont_element *brk_cont_array;
366+
zend_live_range *live_range;
360367
zend_try_catch_element *try_catch_array;
361368

362369
/* static variables support */
@@ -755,7 +762,7 @@ zend_op *get_next_op(zend_op_array *op_array);
755762
void init_op(zend_op *op);
756763
int get_next_op_number(zend_op_array *op_array);
757764
ZEND_API int pass_two(zend_op_array *op_array);
758-
zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array);
765+
zend_brk_cont_element *get_next_brk_cont_element(void);
759766
ZEND_API zend_bool zend_is_compiling(void);
760767
ZEND_API char *zend_make_compiled_string_description(const char *name);
761768
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers);

Zend/zend_execute.c

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,30 +2549,33 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
25492549
{
25502550
int i;
25512551

2552-
for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) {
2553-
const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i];
2554-
if (brk_cont->start < 0) {
2555-
continue;
2556-
} else if (brk_cont->start > op_num) {
2552+
i = EX(func)->op_array.last_live_range;
2553+
while (i) {
2554+
const zend_live_range *range;
2555+
2556+
i--;
2557+
range = &EX(func)->op_array.live_range[i];
2558+
if (range->end <= op_num) {
25572559
/* further blocks will not be relevant... */
25582560
break;
2559-
} else if (op_num < brk_cont->brk) {
2560-
if (!catch_op_num || catch_op_num >= brk_cont->brk) {
2561-
zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk];
2562-
2563-
if (brk_opline->opcode == ZEND_FREE) {
2564-
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
2565-
} else if (brk_opline->opcode == ZEND_FE_FREE) {
2566-
zval *var = EX_VAR(brk_opline->op1.var);
2561+
} else if (op_num >= range->start) {
2562+
if (!catch_op_num || catch_op_num >= range->end) {
2563+
zend_op *opline = &EX(func)->op_array.opcodes[range->end];
2564+
uint32_t var_num = opline->op1.var;
2565+
zval *var = EX_VAR(var_num);
2566+
2567+
if (opline->opcode == ZEND_FREE) {
2568+
zval_ptr_dtor_nogc(var);
2569+
} else if (opline->opcode == ZEND_FE_FREE) {
25672570
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
25682571
zend_hash_iterator_del(Z_FE_ITER_P(var));
25692572
}
25702573
zval_ptr_dtor_nogc(var);
2571-
} else if (brk_opline->opcode == ZEND_ROPE_END) {
2572-
zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var);
2574+
} else if (opline->opcode == ZEND_ROPE_END) {
2575+
zend_string **rope = (zend_string **)var;
25732576
zend_op *last = EX(func)->op_array.opcodes + op_num;
25742577
while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT)
2575-
|| last->result.var != brk_opline->op1.var) {
2578+
|| last->result.var != var_num) {
25762579
ZEND_ASSERT(last >= EX(func)->op_array.opcodes);
25772580
last--;
25782581
}
@@ -2584,10 +2587,10 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
25842587
zend_string_release(rope[j]);
25852588
} while (j--);
25862589
}
2587-
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
2590+
} else if (opline->opcode == ZEND_END_SILENCE) {
25882591
/* restore previous error_reporting value */
2589-
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
2590-
EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var));
2592+
if (!EG(error_reporting) && Z_LVAL_P(var) != 0) {
2593+
EG(error_reporting) = Z_LVAL_P(var);
25912594
}
25922595
}
25932596
}

Zend/zend_opcode.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
7878
op_array->scope = NULL;
7979
op_array->prototype = NULL;
8080

81-
op_array->brk_cont_array = NULL;
81+
op_array->live_range = NULL;
8282
op_array->try_catch_array = NULL;
83-
op_array->last_brk_cont = 0;
83+
op_array->last_live_range = 0;
8484

8585
op_array->static_variables = NULL;
8686
op_array->last_try_catch = 0;
@@ -387,8 +387,8 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
387387
if (op_array->doc_comment) {
388388
zend_string_release(op_array->doc_comment);
389389
}
390-
if (op_array->brk_cont_array) {
391-
efree(op_array->brk_cont_array);
390+
if (op_array->live_range) {
391+
efree(op_array->live_range);
392392
}
393393
if (op_array->try_catch_array) {
394394
efree(op_array->try_catch_array);
@@ -451,11 +451,11 @@ int get_next_op_number(zend_op_array *op_array)
451451
return op_array->last;
452452
}
453453

454-
zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
454+
zend_brk_cont_element *get_next_brk_cont_element(void)
455455
{
456-
op_array->last_brk_cont++;
457-
op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
458-
return &op_array->brk_cont_array[op_array->last_brk_cont-1];
456+
CG(context).last_brk_cont++;
457+
CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont);
458+
return &CG(context).brk_cont_array[CG(context).last_brk_cont-1];
459459
}
460460

461461
static void zend_update_extended_info(zend_op_array *op_array)
@@ -570,7 +570,7 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze
570570
int array_offset = opline->op1.num;
571571
zend_brk_cont_element *jmp_to;
572572
do {
573-
jmp_to = &op_array->brk_cont_array[array_offset];
573+
jmp_to = &CG(context).brk_cont_array[array_offset];
574574
if (nest_levels > 1) {
575575
array_offset = jmp_to->parent;
576576
}

0 commit comments

Comments
 (0)