summaryrefslogtreecommitdiff
path: root/Zend/zend_opcode.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-07-07 15:41:12 +0300
committerDmitry Stogov <dmitry@zend.com>2015-07-07 15:41:12 +0300
commit5ee841325901a4b040cfea56292a24702fe224d9 (patch)
tree5b664b68cb7334554b021bda0a2b9637f8093650 /Zend/zend_opcode.c
parent32677f568bf5281167efacb1bb942ef671ae6504 (diff)
downloadphp-git-5ee841325901a4b040cfea56292a24702fe224d9.tar.gz
Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)
Squashed commit of the following: commit 38e22106d4bdcc829dd2b64be1d3c6cdc089f3ed Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 15:12:19 2015 +0300 Added NEWS entry commit 0a355935bfb10b5a4c893f4db9496ea8abbcf71b Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 15:06:32 2015 +0300 Inline function, to eliminate repeatable checks commit d937584f3aef0baae6001377b61fd700b6f36e14 Merge: 0341626 32677f5 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 14:35:49 2015 +0300 Merge branch 'master' into temporary_cleaning * master: Fixed bug #70006 (cli - function with default arg = STDOUT crash output). Fix x86 build Fixed use after free on closure_call_leak_with_exception.phpt Fixed test commit 0341626ea94a5e474c660732d33884460847d5e7 Merge: 74869fa dec35de Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 12:00:53 2015 +0300 Merge branch 'temporary_cleaning' of https://github.com/laruence/php-src into temporary_cleaning * 'temporary_cleaning' of https://github.com/laruence/php-src: Fixed checkpoint get Fixed crash of invalid pointer derefer cleanup commit 74869fa67375b8daf772ac30b6b936fd2a2132c6 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 11:45:34 2015 +0300 Fixed wrong GOTO resolution commit dec35ded3294e3022e88a623188c3d1d71381675 Author: Xinchen Hui <laruence@gmail.com> Date: Tue Jul 7 15:58:49 2015 +0800 Fixed checkpoint get commit b0f419540ad24c44810c9b05da046965618ffc65 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 10:47:11 2015 +0300 Fixed crash of invalid pointer derefer (laruence) commit 7a428d98ca2899c5933914caa0cd17b4126e952c Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 10:35:47 2015 +0300 Fixed identation commit 9c3a4dce9ce02034d19d28182aa9c1298d528daf Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 10:33:52 2015 +0300 Fixed invalid size commit 653abc670b2a1f453b0fc3fc4a9eca919ee870cc Author: Xinchen Hui <laruence@gmail.com> Date: Tue Jul 7 11:29:14 2015 +0800 Fixed crash of invalid pointer derefer commit e04500ceda606ac4f364d03bcd562327bdc74eee Author: Xinchen Hui <laruence@gmail.com> Date: Tue Jul 7 11:28:26 2015 +0800 cleanup commit 34183e1687681038e77b650078927b35ee84e933 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 04:49:46 2015 +0300 op_array->T_liveliness compression commit 2f6ad845795a08c3d7ac219e9c42950565b20394 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 04:44:44 2015 +0300 White spaces commit be83f115a3f82a548c8d377c66574de5e5187410 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 04:42:26 2015 +0300 Identation commit 1f5084b99038c374ac012b017c4d1652bb5d4222 Merge: 91b620d 1adf3df Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 04:41:54 2015 +0300 Merge branch 'master' into temporary_cleaning * master: Throw TypeError for invalid callback Fix crash when exception occurs during nested rope Fix crash when exception is thrown during ROPE_END Small cleanup in ternary compilation move the define to the right place fix ext/ldap build Rectify information about invalid shift warning being now ArithmeticError commit 91b620d684c5a2296774432d5d0ff8f5d14397d6 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 04:32:04 2015 +0300 Replace GOTO by FREE/FE_FREE and JMP at compile time commit 7052e5697918fab83d2975977c3392f7188fbc87 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Jul 7 02:25:08 2015 +0300 Use zend_regenerate_var_liveliness_info() to regenerate information after pass two. commit ae72b0dc6797815a846b8f95abccb36367422d27 Merge: a81c4bb a919fe8 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 21:02:34 2015 +0300 Merge branch 'master' into temporary_cleaning * master: Do not display EXT_TYPE_UNUSED in phpdbg opcodes Run debug build with opcache on travis commit a81c4bb8c6f1ba8124a5a7636694480ff0f1328c Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 20:59:34 2015 +0300 Improved algorithm. It's actually the same algorithm with second loop removed and simpler temporary data structures. The only difference may be in "re-defined" vatriable handling. Now live-range in that case started from the seconnd definition (this must be more safe). commit 9a16810f7a7c10373603c5250d985616acf45e97 Merge: bbfbe47 001ecd3 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 17:57:45 2015 +0300 Merge branch 'master' into temporary_cleaning * master: Simplify TMP var number decoding (without HashTable) commit bbfbe470c865cb8b3cae8bf6518e6d06af525522 Merge: 0bda4ab 436b01e Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 17:02:01 2015 +0300 Merge branch 'master' into temporary_cleaning * master: Avoid dangerous optimization Fixed JMPZNZ instruction printing Attempt at falling back on ldap_find_control for Mac OS commit 0bda4abea7ba0a51c2ec125edb547645d0329792 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 16:05:33 2015 +0300 Fixed live-range construction for OP_DATA opcode Added comments about algorithm assumtions commit 521ad9df98fdf1dd8b7c212799ddeb1a84483e6f Merge: 4398dab a09dcb0 Author: Bob Weinand <bobwei9@hotmail.com> Date: Mon Jul 6 14:54:15 2015 +0200 Merge branch 'master' of https://github.com/php/php-src into temporary_cleaning commit 4398dab82f9a5ce64df55b24988ce7d31e24074f Author: Bob Weinand <bobwei9@hotmail.com> Date: Mon Jul 6 13:51:27 2015 +0200 Add a few phpt tests related to temporary cleaning commit 739656f83ff5b570bb311d2c7cb2d72380a3c759 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 14:28:49 2015 +0300 Fixed Zend/tests/foreach_004.phpt failure (FE_FETCH shouldn't be included into TMP vatriablr live range) commit 3df462a2bcf5fa8f9244ea299178152a5d436277 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 13:41:02 2015 +0300 Improve data layout (reduce the op_array structure size on 64-bit systems) commit 883b73c56e6dab6489ae4cda2c1331b53a995586 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Jul 6 13:28:45 2015 +0300 Removed op_array->brk_cont_array commit ae5e58b59843513505e84e396c1446ac35cb1b94 Author: Bob Weinand <bobwei9@hotmail.com> Date: Mon Jul 6 04:22:58 2015 +0200 Fix bug with brk_cont variable free / free loop vars via temporary liveliness info commit b4223ca62771e1003c9ab778a09a177ad71e6d57 Author: Bob Weinand <bobwei9@hotmail.com> Date: Mon Jul 6 04:07:07 2015 +0200 Fix bugs / cleanup fixes commit ea33189d220c7fc0884848571635abe3cddd2f4d Author: Xinchen Hui <laruence@gmail.com> Date: Sun Jul 5 20:58:38 2015 +0800 Removed useless TsTop commit 1dbb007e4addba9ac3bfc227db27a651cbcf5ede Merge: 550bbf8 3a8af24 Author: Xinchen Hui <laruence@gmail.com> Date: Sat Jul 4 15:06:44 2015 +0800 Merge branch 'temporary_cleaning' of https://github.com/dstogov/php-src into temporary_cleaning commit 3a8af245290ceb507108340831254672f24022fa Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 3 16:15:36 2015 +0300 More exceptions from regular liveliness analyses (with explanation in comments). Mark old "unexplained" exceptions with ???. commit ba721efa2cbd2136668fec956ef3b034ac1a29d6 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 3 14:16:09 2015 +0300 Print list of live temp variables (at least for internal debugging) commit 8d1f88fe91e62b4333703c58b871d85b66fb7b70 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 3 13:31:56 2015 +0300 Use op_array->T_liveliness to free incomplete ropes and restore error_reporting level on exception commit 80c1d0d779e6e9609a211907838f3727aa7b301a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 3 11:05:39 2015 +0300 Don't keep empty T_liveliness commit 501ae8aaac0a92368b50e9f342b04d7334d263f6 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jul 2 22:31:48 2015 +0300 Reverted changes to Zend/zend_arena.h. Reuse CG(arena) instead of creating a new one. commit a4fce36907147df5ac1af78b44135e3f07c1844c Merge: 6ff7246 fd0fcce Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jul 2 22:01:42 2015 +0300 Merge branch 'temporary_cleaning' of github.com:bwoebi/php-src into temporary_cleaning * 'temporary_cleaning' of github.com:bwoebi/php-src: Fix remaining issues with compacted temporaries Fix regression from last commit (+1 ?!) Fix off-by-one (opcache may remove last ZEND_RETURN) Speed algorithm up, more fail safety when reusing temporaries Dumb bug in opcode.c (forgot to update Ts[i]) Fix opcache support Exempt ROPE temporaries from freeing Hmm, we need temporary info for all the opcodes Add opcache support for cleaning in optimization step (Opcache seems to have a few unrelated issues which blow up together with that patch) Add proper temporary cleaning upon frame abortion Fix arena on small sizes (size < sizeof(zend_arena)) commit fd0fcce81177717f3a05ac87192b5ed05eead0a1 Author: Bob Weinand <bobwei9@hotmail.com> Date: Thu Jul 2 20:00:33 2015 +0200 Fix remaining issues with compacted temporaries commit 427dc58bbb93022d1c2077f874afcdb9dd82d5c5 Author: Bob Weinand <bobwei9@hotmail.com> Date: Wed Jul 1 22:49:12 2015 +0200 Fix regression from last commit (+1 ?!) commit 1adcf56a6e9f09e7ad06331d4d6280035b17a7d1 Author: Bob Weinand <bobwei9@hotmail.com> Date: Wed Jul 1 22:17:07 2015 +0200 Fix off-by-one (opcache may remove last ZEND_RETURN) commit 25b231b7841fa4078c65976cabdd843845a6cbe6 Author: Bob Weinand <bobwei9@hotmail.com> Date: Wed Jul 1 20:59:24 2015 +0200 Speed algorithm up, more fail safety when reusing temporaries commit 22d9d05350e35d180018d0bccbad6f173cb4797d Author: Bob Weinand <bobwei9@hotmail.com> Date: Wed Jul 1 16:48:46 2015 +0200 Dumb bug in opcode.c (forgot to update Ts[i]) commit 6538269bfa5bcbad34fc2f051b0fd5e4ebf2ff00 Author: Bob Weinand <bobwei9@hotmail.com> Date: Wed Jul 1 13:05:52 2015 +0200 Fix opcache support commit 333a7c4a8813a45dc79ce55b8e9c0a0b98671e13 Author: Bob Weinand <bobwei9@hotmail.com> Date: Sat Jun 27 22:40:21 2015 +0200 Exempt ROPE temporaries from freeing commit 02585f77085427baea48448c134a96c542af3337 Author: Bob Weinand <bobwei9@hotmail.com> Date: Fri Jun 26 16:20:55 2015 +0200 Hmm, we need temporary info for all the opcodes commit cbcaedbd78199897e5cacffd700b706f21590abf Author: Bob Weinand <bobwei9@hotmail.com> Date: Fri Jun 26 01:04:09 2015 +0200 Add opcache support for cleaning in optimization step (Opcache seems to have a few unrelated issues which blow up together with that patch) commit fef649f4067823a1f96f85340cf715e5877310bc Author: Bob Weinand <bobwei9@hotmail.com> Date: Fri Jun 26 01:02:27 2015 +0200 Add proper temporary cleaning upon frame abortion commit 1cec2e7271b789b84601f8acf385950af1bb0c7c Author: Bob Weinand <bobwei9@hotmail.com> Date: Thu Jun 25 23:33:21 2015 +0200 Fix arena on small sizes (size < sizeof(zend_arena))
Diffstat (limited to 'Zend/zend_opcode.c')
-rw-r--r--Zend/zend_opcode.c237
1 files changed, 222 insertions, 15 deletions
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index a971a5e900..8f3ecddbda 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -65,6 +65,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->vars = NULL;
op_array->T = 0;
+ op_array->T_liveliness = NULL;
op_array->function_name = NULL;
op_array->filename = zend_get_compiled_filename();
@@ -77,9 +78,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->scope = NULL;
op_array->prototype = NULL;
- op_array->brk_cont_array = NULL;
op_array->try_catch_array = NULL;
- op_array->last_brk_cont = 0;
op_array->static_variables = NULL;
op_array->last_try_catch = 0;
@@ -383,12 +382,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
if (op_array->doc_comment) {
zend_string_release(op_array->doc_comment);
}
- if (op_array->brk_cont_array) {
- efree(op_array->brk_cont_array);
- }
if (op_array->try_catch_array) {
efree(op_array->try_catch_array);
}
+ if (op_array->T_liveliness) {
+ efree(op_array->T_liveliness);
+ }
if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
}
@@ -447,9 +446,9 @@ int get_next_op_number(zend_op_array *op_array)
zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
{
- op_array->last_brk_cont++;
- op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
- return &op_array->brk_cont_array[op_array->last_brk_cont-1];
+ CG(context).last_brk_cont++;
+ CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element)*CG(context).last_brk_cont);
+ return &CG(context).brk_cont_array[CG(context).last_brk_cont-1];
}
static void zend_update_extended_info(zend_op_array *op_array)
@@ -576,7 +575,7 @@ static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num,
fast_call_var = op_array->opcodes[op_array->try_catch_array[i].finally_end].op1.var;
/* generate a FAST_CALL to finally block */
- start_op = get_next_op_number(op_array);
+ start_op = get_next_op_number(op_array);
opline = get_next_op(op_array);
opline->opcode = ZEND_FAST_CALL;
@@ -672,7 +671,7 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze
int array_offset = opline->op1.num;
zend_brk_cont_element *jmp_to;
do {
- jmp_to = &op_array->brk_cont_array[array_offset];
+ jmp_to = &CG(context).brk_cont_array[array_offset];
if (nest_levels > 1) {
array_offset = jmp_to->parent;
}
@@ -700,11 +699,8 @@ static void zend_resolve_finally_calls(zend_op_array *op_array)
break;
case ZEND_GOTO:
if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) {
- uint32_t num = opline->op2.constant;
-
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
- zend_resolve_goto_label(op_array, opline, 1);
- opline->op2.constant = num;
+ zend_resolve_goto_label(op_array, NULL, opline);
}
/* break omitted intentionally */
case ZEND_JMP:
@@ -751,6 +747,9 @@ ZEND_API int pass_two(zend_op_array *op_array)
op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
CG(context).literals_size = op_array->last_literal;
}
+
+ zend_generate_var_liveliness_info(op_array);
+
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -787,7 +786,7 @@ ZEND_API int pass_two(zend_op_array *op_array)
break;
case ZEND_GOTO:
if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) {
- zend_resolve_goto_label(op_array, opline, 1);
+ zend_resolve_goto_label(op_array, NULL, opline);
}
/* break omitted intentionally */
case ZEND_JMP:
@@ -840,6 +839,214 @@ int pass_two_wrapper(zval *el)
return pass_two((zend_op_array *) Z_PTR_P(el));
}
+/* The following liveliness analyzing algorithm assumes that
+ * 1) temporary variables are defined before use
+ * 2) they have linear live-ranges without "holes"
+ * 3) Opcodes never use and define the same temorary variables
+ */
+typedef struct _op_var_info {
+ struct _op_var_info *next;
+ uint32_t var;
+} op_var_info;
+
+static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array, zend_op *cur_op, uint32_t var, uint32_t *Tstart, op_var_info **opTs)
+{
+ uint32_t start = Tstart[var];
+ uint32_t end = cur_op - op_array->opcodes;
+ uint32_t count = 0;
+ uint32_t var_offset, j;
+
+ Tstart[var] = -1;
+ if (cur_op->opcode == ZEND_OP_DATA) {
+ end--;
+ }
+ start++;
+ if (op_array->opcodes[start].opcode == ZEND_OP_DATA
+ || op_array->opcodes[start].opcode == ZEND_FE_FETCH_R
+ || op_array->opcodes[start].opcode == ZEND_FE_FETCH_RW) {
+ start++;
+ }
+ if (start < end) {
+ op_var_info *new_opTs;
+
+ var_offset = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var);
+ if (op_array->opcodes[end].opcode == ZEND_ROPE_END) {
+ var_offset |= ZEND_LIVE_ROPE;
+ } else if (op_array->opcodes[end].opcode == ZEND_END_SILENCE) {
+ var_offset |= ZEND_LIVE_SILENCE;
+ } else if (op_array->opcodes[end].opcode == ZEND_FE_FREE) {
+ var_offset |= ZEND_LIVE_LOOP;
+ }
+
+ if (opTs[start]) {
+ if (start > 0 && opTs[start-1] == opTs[start]) {
+ op_var_info *opT = opTs[start];
+ do {
+ count++;
+ opT = opT->next;
+ } while (opT);
+ count += 2;
+ } else {
+ count++;
+ }
+ } else {
+ count += 2;
+ }
+
+ new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
+ new_opTs->next = opTs[start];
+ new_opTs->var = var_offset;
+ opTs[start] = new_opTs;
+
+ for (j = start + 1; j < end; j++) {
+ if (opTs[j-1]->next == opTs[j]) {
+ opTs[j] = opTs[j-1];
+ } else {
+ if (opTs[j]) {
+ count++;
+ } else {
+ count += 2;
+ }
+ new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
+ new_opTs->next = opTs[j];
+ new_opTs->var = var_offset;
+ opTs[j] = new_opTs;
+ }
+ }
+ }
+
+ return count;
+}
+
+static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_array *op_array, zend_bool done_pass_two)
+{
+ zend_op *opline, *end;
+ uint32_t var, i, op_live_total = 0;
+ uint32_t *info, info_off = op_array->last + 1;
+ void *checkpoint = zend_arena_checkpoint(CG(arena));
+ uint32_t *Tstart = zend_arena_alloc(&CG(arena), sizeof(uint32_t) * op_array->T);
+ op_var_info **opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info *) * op_array->last);
+
+ memset(Tstart, -1, sizeof(uint32_t) * op_array->T);
+ memset(opTs, 0, sizeof(op_var_info *) * op_array->last);
+
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ do {
+ if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
+ && !((opline)->result_type & EXT_TYPE_UNUSED)
+ /* the following opcodes are used in inline branching
+ * (and anyway always bool, so no need to free) and may
+ * not be defined depending on the taken branch */
+ && opline->opcode != ZEND_BOOL
+ && opline->opcode != ZEND_JMPZ_EX
+ && opline->opcode != ZEND_JMPNZ_EX
+ /* these two consecutive ops appear on ternary,
+ * the result of true branch is undefined for false branch */
+ && (opline->opcode != ZEND_QM_ASSIGN || (opline + 1)->opcode != ZEND_JMP)
+ /* exception for opcache, it might nowhere use the temporary
+ * (anyway bool, so no need to free) */
+ && opline->opcode != ZEND_CASE
+ /* the following opcodes reuse TMP created before */
+ && opline->opcode != ZEND_ROPE_ADD
+ && opline->opcode != ZEND_ADD_ARRAY_ELEMENT
+ /* passes fast_call */
+ && opline->opcode != ZEND_FAST_CALL
+ /* the following opcodes pass class_entry */
+ && opline->opcode != ZEND_FETCH_CLASS
+ && opline->opcode != ZEND_DECLARE_CLASS
+ && opline->opcode != ZEND_DECLARE_INHERITED_CLASS
+ && opline->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED
+ && opline->opcode != ZEND_DECLARE_ANON_CLASS
+ && opline->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) {
+ if (done_pass_two) {
+ var = EX_VAR_TO_NUM(opline->result.var) - op_array->last_var;
+ } else {
+ var = opline->result.var;
+ }
+ /* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */
+ if (opline->opcode == ZEND_NEW) {
+ Tstart[var] = opline->op2.opline_num - 1;
+ } else {
+ Tstart[var] = opline - op_array->opcodes;
+ }
+ }
+ if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
+ if (done_pass_two) {
+ var = EX_VAR_TO_NUM(opline->op1.var) - op_array->last_var;
+ } else {
+ var = opline->op1.var;
+ }
+ if (Tstart[var] != (uint32_t)-1
+ /* the following opcodes don't free TMP */
+ && opline->opcode != ZEND_ROPE_ADD
+ && opline->opcode != ZEND_FETCH_LIST
+ && opline->opcode != ZEND_CASE
+ && opline->opcode != ZEND_FE_FETCH_R
+ && opline->opcode != ZEND_FE_FETCH_RW) {
+ op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
+ }
+ }
+ if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
+ if (done_pass_two) {
+ var = EX_VAR_TO_NUM(opline->op2.var) - op_array->last_var;
+ } else {
+ var = opline->op2.var;
+ }
+ if (Tstart[var] != (uint32_t)-1) {
+ op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
+ }
+ }
+ } while (++opline != end);
+
+#if ZEND_DEBUG
+ /* Check that all TMP variable live-ranges are closed */
+ for (i = 0; i < op_array->T; i++) {
+ ZEND_ASSERT(Tstart[i] == (uint32_t)-1);
+ }
+#endif
+
+ if (!op_live_total) {
+ info = NULL;
+ } else {
+ info = emalloc((op_array->last + 1 + op_live_total) * sizeof(uint32_t));
+
+ for (i = 0; i < op_array->last; i++) {
+ if (!opTs[i]) {
+ info[i] = (uint32_t)-1;
+ } else if (i > 0 && opTs[i-1] == opTs[i]) {
+ info[i] = info[i-1];
+ } else {
+ op_var_info *opT = opTs[i];
+ info[i] = info_off;
+ while (opT) {
+ info[info_off++] = opT->var;
+ opT = opT->next;
+ }
+ info[info_off++] = (uint32_t)-1;
+ }
+ }
+ info[op_array->last] = info_off;
+ ZEND_ASSERT(info_off == op_array->last + 1 + op_live_total);
+ }
+
+ zend_arena_release(&CG(arena), checkpoint);
+ return info;
+}
+
+ZEND_API void zend_generate_var_liveliness_info(zend_op_array *op_array)
+{
+ op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 0);
+}
+
+ZEND_API void zend_regenerate_var_liveliness_info(zend_op_array *op_array)
+{
+ if (op_array->T_liveliness) {
+ efree(op_array->T_liveliness);
+ }
+ op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 1);
+}
+
int print_class(zend_class_entry *class_entry)
{
printf("Class %s:\n", ZSTR_VAL(class_entry->name));