From 90cb3bb7de3b7f4707a15cd6214c5d6aefda0057 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 6 Aug 2015 15:41:50 +0300 Subject: [PATCH] Reduce memory usage by using bitsets instead of array of bytes. --- Zend/zend_bitset.h | 185 +++++++++++++++++++ ext/opcache/Optimizer/block_pass.c | 64 ++++--- ext/opcache/Optimizer/optimize_temp_vars_5.c | 69 +++---- 3 files changed, 256 insertions(+), 62 deletions(-) create mode 100644 Zend/zend_bitset.h diff --git a/Zend/zend_bitset.h b/Zend/zend_bitset.h new file mode 100644 index 00000000000..e3c2ec748d5 --- /dev/null +++ b/Zend/zend_bitset.h @@ -0,0 +1,185 @@ +/* + +----------------------------------------------------------------------+ + | Zend OPcache JIT | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov | + +----------------------------------------------------------------------+ +*/ + +/* $Id:$ */ + +#ifndef _ZEND_BITSET_H_ +#define _ZEND_BITSET_H_ + +typedef zend_ulong *zend_bitset; + +#define ZEND_BITSET_ELM_SIZE sizeof(zend_ulong) + +#if SIZEOF_ZEND_LONG == 4 +# define ZEND_BITSET_ELM_NUM(n) ((n) >> 5) +# define ZEND_BITSET_BIT_NUM(n) ((zend_ulong)(n) & Z_UL(0x1f)) +#elif SIZEOF_ZEND_LONG == 8 +# define ZEND_BITSET_ELM_NUM(n) ((n) >> 6) +# define ZEND_BITSET_BIT_NUM(n) ((zend_ulong)(n) & Z_UL(0x3f)) +#else +# define ZEND_BITSET_ELM_NUM(n) ((n) / (sizeof(zend_long) * 8)) +# define ZEND_BITSET_BIT_NUM(n) ((n) % (sizeof(zend_long) * 8)) +#endif + +/* Returns the number of zend_ulong words needed to store a bitset that is N + bits long. */ +static inline uint32_t zend_bitset_len(uint32_t n) +{ + return (n + ((sizeof(zend_long) * 8) - 1)) / (sizeof(zend_long) * 8); +} + +#define ZEND_BITSET_ALLOCA(n, use_heap) \ + (zend_bitset)do_alloca((n) * ZEND_BITSET_ELM_SIZE, use_heap) + +static inline zend_bool zend_bitset_in(zend_bitset set, uint32_t n) +{ + return (set[ZEND_BITSET_ELM_NUM(n)] & (Z_UL(1) << ZEND_BITSET_BIT_NUM(n))) != Z_UL(0); +} + +static inline void zend_bitset_incl(zend_bitset set, uint32_t n) +{ + set[ZEND_BITSET_ELM_NUM(n)] |= Z_UL(1) << ZEND_BITSET_BIT_NUM(n); +} + +static inline void zend_bitset_excl(zend_bitset set, uint32_t n) +{ + set[ZEND_BITSET_ELM_NUM(n)] &= ~(Z_UL(1) << ZEND_BITSET_BIT_NUM(n)); +} + +static inline void zend_bitset_clear(zend_bitset set, uint32_t len) +{ + memset(set, 0, len * ZEND_BITSET_ELM_SIZE); +} + +static inline int zend_bitset_empty(zend_bitset set, uint32_t len) +{ + uint32_t i; + for (i = 0; i < len; i++) { + if (set[i]) { + return 0; + } + } + return 1; +} + +static inline void zend_bitset_fill(zend_bitset set, uint32_t len) +{ + memset(set, 0xff, len * ZEND_BITSET_ELM_SIZE); +} + +static inline zend_bool zend_bitset_equal(zend_bitset set1, zend_bitset set2, uint32_t len) +{ + return memcmp(set1, set2, len * ZEND_BITSET_ELM_SIZE) == 0; +} + +static inline void zend_bitset_copy(zend_bitset set1, zend_bitset set2, uint32_t len) +{ + memcpy(set1, set2, len * ZEND_BITSET_ELM_SIZE); +} + +static inline void zend_bitset_intersection(zend_bitset set1, zend_bitset set2, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + set1[i] &= set2[i]; + } +} + +static inline void zend_bitset_union(zend_bitset set1, zend_bitset set2, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + set1[i] |= set2[i]; + } +} + +static inline void zend_bitset_difference(zend_bitset set1, zend_bitset set2, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + set1[i] = set1[i] & ~set2[i]; + } +} + +static inline void zend_bitset_union_with_intersection(zend_bitset set1, zend_bitset set2, zend_bitset set3, zend_bitset set4, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + set1[i] = set2[i] | (set3[i] & set4[i]); + } +} + +static inline void zend_bitset_union_with_difference(zend_bitset set1, zend_bitset set2, zend_bitset set3, zend_bitset set4, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + set1[i] = set2[i] | (set3[i] & ~set4[i]); + } +} + +static inline int zend_bitset_first(zend_bitset set, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + if (set[i]) { + int j = ZEND_BITSET_ELM_SIZE * 8 * i; + zend_ulong x = set[i]; + while ((x & Z_UL(1)) == 0) { + x = x >> Z_UL(1); + j++; + } + return j; + } + } + return -1; /* empty set */ +} + +static inline int zend_bitset_last(zend_bitset set, uint32_t len) +{ + uint32_t i = len; + + while (i > 0) { + i--; + if (set[i]) { + int j = ZEND_BITSET_ELM_SIZE * 8 * i - 1; + zend_ulong x = set[i]; + while (x != Z_UL(0)) { + x = x >> Z_UL(1); + j++; + } + return j; + } + } + return -1; /* empty set */ +} + +#endif /* _ZEND_BITSET_H_ */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 8b29d21f796..a73041880bc 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -26,6 +26,7 @@ #include "zend_constants.h" #include "zend_execute.h" #include "zend_vm.h" +#include "zend_bitset.h" #define DEBUG_BLOCKPASS 0 @@ -601,7 +602,7 @@ static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx) block->len = new_end - block->start_opline; } -static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, char *used_ext, zend_cfg *cfg, zend_optimizer_ctx *ctx) +static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_cfg *cfg, zend_optimizer_ctx *ctx) { zend_op *opline = block->start_opline; zend_op *end, *last_op = NULL; @@ -799,7 +800,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline->opcode == ZEND_JMPZNZ) && ZEND_OP1_TYPE(opline) == IS_TMP_VAR && VAR_SOURCE(opline->op1) != NULL && - !used_ext[VAR_NUM(ZEND_OP1(opline).var)] && + !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) && VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT) { /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */ zend_op *src = VAR_SOURCE(opline->op1); @@ -874,7 +875,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline->opcode == ZEND_JMPZNZ) && (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) && VAR_SOURCE(opline->op1) != NULL && - (!used_ext[VAR_NUM(ZEND_OP1(opline).var)] || + (!zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) || ((ZEND_RESULT_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) && ZEND_RESULT(opline).var == ZEND_OP1(opline).var)) && (VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL || @@ -1112,7 +1113,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_IDENTICAL || VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_VAR || VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) && - !used_ext[VAR_NUM(ZEND_OP1(opline).var)]) { + !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var))) { /* T = IS_SMALLER(X, Y), T1 = BOOL(T) => T = IS_SMALLER(X, Y), T1 = QM_ASSIGN(T) */ zend_op *src = VAR_SOURCE(opline->op1); COPY_NODE(src->result, opline->result); @@ -1771,21 +1772,22 @@ next_target_znz: #define T_USAGE(op) do { \ if ((op ## _type & (IS_VAR | IS_TMP_VAR)) && \ - !defined_here[VAR_NUM(op.var)] && !used_ext[VAR_NUM(op.var)]) { \ - used_ext[VAR_NUM(op.var)] = 1; \ + !zend_bitset_in(defined_here, VAR_NUM(op.var)) && !zend_bitset_in(used_ext, VAR_NUM(op.var))) { \ + zend_bitset_incl(used_ext, VAR_NUM(op.var)); \ } \ } while (0) -#define NEVER_USED(op) ((op ## _type & (IS_VAR | IS_TMP_VAR)) && !usage[VAR_NUM(op.var)]) /* !used_ext[op.var] && */ +#define NEVER_USED(op) ((op ## _type & (IS_VAR | IS_TMP_VAR)) && !zend_bitset_in(usage, VAR_NUM(op.var))) /* !zend_bitset_in(used_ext, op.var) && */ #define RES_NEVER_USED(opline) (opline->result_type == IS_UNUSED || NEVER_USED(opline->result)) /* Find a set of variables which are used outside of the block where they are * defined. We won't apply some optimization patterns for such variables. */ -static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *used_ext, zend_optimizer_ctx *ctx) +static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_optimizer_ctx *ctx) { zend_code_block *next_block = block->next; - char *usage; - char *defined_here; + uint32_t bitset_len; + zend_bitset usage; + zend_bitset defined_here; void *checkpoint; if (op_array->T == 0) { @@ -1794,9 +1796,10 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * } checkpoint = zend_arena_checkpoint(ctx->arena); - usage = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T); - memset(usage, 0, op_array->last_var + op_array->T); - defined_here = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T); + bitset_len = zend_bitset_len(op_array->last_var + op_array->T); + usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); + zend_bitset_clear(usage, bitset_len); + defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); while (next_block) { zend_op *opline = next_block->start_opline; @@ -1806,26 +1809,26 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * next_block = next_block->next; continue; } - memset(defined_here, 0, op_array->last_var + op_array->T); + zend_bitset_clear(defined_here, bitset_len); while (oplineop1); if (opline->op2_type & (IS_VAR | IS_TMP_VAR)) { if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { /* these opcode use the op2 as result */ - defined_here[VAR_NUM(ZEND_OP2(opline).var)] = 1; + zend_bitset_incl(defined_here, VAR_NUM(ZEND_OP2(opline).var)); } else { T_USAGE(opline->op2); } } if (RESULT_USED(opline)) { - if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] && + if (!zend_bitset_in(defined_here, VAR_NUM(ZEND_RESULT(opline).var)) && !zend_bitset_in(used_ext, VAR_NUM(ZEND_RESULT(opline).var)) && opline->opcode == ZEND_ADD_ARRAY_ELEMENT) { /* these opcode use the result as argument */ - used_ext[VAR_NUM(ZEND_RESULT(opline).var)] = 1; + zend_bitset_incl(used_ext, VAR_NUM(ZEND_RESULT(opline).var)); } - defined_here[VAR_NUM(ZEND_RESULT(opline).var)] = 1; + zend_bitset_incl(defined_here, VAR_NUM(ZEND_RESULT(opline).var)); } opline++; } @@ -1836,7 +1839,7 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * { int i; for (i = op_array->last_var; i< op_array->T; i++) { - fprintf(stderr, "T%d: %c\n", i, used_ext[i] + '0'); + fprintf(stderr, "T%d: %c\n", i, zend_bitset_in(used_ext, i) + '0'); } } #endif @@ -1849,7 +1852,7 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * continue; } - memcpy(usage, used_ext, op_array->last_var + op_array->T); + zend_bitset_copy(usage, used_ext, bitset_len); while (opline >= block->start_opline) { /* usage checks */ @@ -1898,25 +1901,25 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * if (opline->opcode == ZEND_ADD_ARRAY_ELEMENT) { if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) { - usage[VAR_NUM(ZEND_RESULT(opline).var)] = 1; + zend_bitset_incl(usage, VAR_NUM(ZEND_RESULT(opline).var)); } } else { if (RESULT_USED(opline)) { - usage[VAR_NUM(ZEND_RESULT(opline).var)] = 0; + zend_bitset_excl(usage, VAR_NUM(ZEND_RESULT(opline).var)); } } if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) { - usage[VAR_NUM(ZEND_OP1(opline).var)] = 1; + zend_bitset_incl(usage, VAR_NUM(ZEND_OP1(opline).var)); } if (ZEND_OP2_TYPE(opline) == IS_VAR || ZEND_OP2_TYPE(opline) == IS_TMP_VAR) { - usage[VAR_NUM(ZEND_OP2(opline).var)] = 1; + zend_bitset_incl(usage, VAR_NUM(ZEND_OP2(opline).var)); } if ((ZEND_RESULT_TYPE(opline) & IS_VAR) && (ZEND_RESULT_TYPE(opline) & EXT_TYPE_UNUSED) && - usage[VAR_NUM(ZEND_RESULT(opline).var)]) { + zend_bitset_in(usage, VAR_NUM(ZEND_RESULT(opline).var))) { ZEND_RESULT_TYPE(opline) &= ~EXT_TYPE_UNUSED; } @@ -1935,7 +1938,8 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_cfg cfg; zend_code_block *cur_block; int pass; - char *usage; + uint32_t bitset_len; + zend_bitset usage; void *checkpoint; #if DEBUG_BLOCKPASS @@ -1957,17 +1961,19 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_rebuild_access_path(&cfg, op_array, 0, ctx); /* full rebuild here to produce correct sources! */ if (op_array->last_var || op_array->T) { + bitset_len = zend_bitset_len(op_array->last_var + op_array->T); cfg.Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *)); cfg.same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T); - usage = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T); + usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); } else { + bitset_len = 0; cfg.Tsource = NULL; cfg.same_t = NULL; usage = NULL; } for (pass = 0; pass < PASSES; pass++) { /* Compute data dependencies */ - memset(usage, 0, op_array->last_var + op_array->T); + zend_bitset_clear(usage, bitset_len); zend_t_usage(cfg.blocks, op_array, usage, ctx); /* optimize each basic block separately */ @@ -1990,7 +1996,7 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_rebuild_access_path(&cfg, op_array, 1, ctx); } - memset(usage, 0, op_array->last_var + op_array->T); + zend_bitset_clear(usage, bitset_len); zend_t_usage(cfg.blocks, op_array, usage, ctx); assemble_code_blocks(&cfg, op_array); diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c index f60f61cb452..0e96ee86242 100644 --- a/ext/opcache/Optimizer/optimize_temp_vars_5.c +++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c @@ -26,25 +26,27 @@ #include "zend_constants.h" #include "zend_execute.h" #include "zend_vm.h" +#include "zend_bitset.h" -#define GET_AVAILABLE_T() \ - for (i = 0; i < T; i++) { \ - if (!taken_T[i]) { \ - break; \ - } \ - } \ - taken_T[i] = 1; \ - if (i > max) { \ - max = i; \ +#define GET_AVAILABLE_T() \ + for (i = 0; i < T; i++) { \ + if (!zend_bitset_in(taken_T, i)) { \ + break; \ + } \ + } \ + zend_bitset_incl(taken_T, i); \ + if (i > max) { \ + max = i; \ } void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; - char *taken_T; /* T index in use */ + uint32_t bitset_len; + zend_bitset taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ - char *valid_T; /* Is the map_T valid */ + zend_bitset valid_T; /* Is the map_T valid */ int *map_T; /* Map's the T to its new index */ zend_op *opline, *end; int currT; @@ -53,9 +55,10 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); - taken_T = (char *) zend_arena_alloc(&ctx->arena, T); + bitset_len = zend_bitset_len(T); + taken_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); - valid_T = (char *) zend_arena_alloc(&ctx->arena, T); + valid_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); end = op_array->opcodes; @@ -69,8 +72,8 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline--; } - memset(valid_T, 0, T); - memset(taken_T, 0, T); + zend_bitset_clear(valid_T, bitset_len); + zend_bitset_clear(taken_T, bitset_len); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; @@ -83,24 +86,24 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c int var; var = max; - while (var >= 0 && !taken_T[var]) { + while (var >= 0 && !zend_bitset_in(taken_T, var)) { var--; } max = MAX(max, var + num); var = var + 1; map_T[currT] = var; - valid_T[currT] = 1; - taken_T[var] = 1; + zend_bitset_incl(valid_T, currT); + zend_bitset_incl(taken_T, var); ZEND_OP1(opline).var = NUM_VAR(var + offset); while (num > 1) { num--; - taken_T[var + num] = 1; + zend_bitset_incl(taken_T, var + num); } } else { - if (!valid_T[currT]) { + if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; - valid_T[currT] = 1; + zend_bitset_incl(valid_T, currT); } ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset); } @@ -115,10 +118,10 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; - if (!valid_T[currT]) { + if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; - valid_T[currT] = 1; + zend_bitset_incl(valid_T, currT); } ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset); } @@ -127,10 +130,10 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { currT = VAR_NUM(opline->extended_value) - offset; - if (!valid_T[currT]) { + if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; - valid_T[currT] = 1; + zend_bitset_incl(valid_T, currT); } opline->extended_value = NUM_VAR(map_T[currT] + offset); } @@ -142,21 +145,21 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c currT = VAR_NUM(ZEND_OP2(opline + 1).var) - offset; GET_AVAILABLE_T(); map_T[currT] = i; - valid_T[currT] = 1; - taken_T[i] = 0; + zend_bitset_incl(valid_T, currT); + zend_bitset_excl(taken_T, i); ZEND_OP2(opline + 1).var = NUM_VAR(i + offset); var_to_free = i; } if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; - if (valid_T[currT]) { + if (zend_bitset_in(valid_T, currT)) { if (start_of_T[currT] == opline) { /* ZEND_FAST_CALL can not share temporary var with others * since the fast_var could also be set by ZEND_HANDLE_EXCEPTION * which could be ahead of it */ if (opline->opcode != ZEND_FAST_CALL) { - taken_T[map_T[currT]] = 0; + zend_bitset_excl(taken_T, map_T[currT]); } } ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset); @@ -165,7 +168,7 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); while (num > 1) { num--; - taken_T[map_T[currT]+num] = 0; + zend_bitset_excl(taken_T, map_T[currT]+num); } } } @@ -173,18 +176,18 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c GET_AVAILABLE_T(); if (RESULT_UNUSED(opline)) { - taken_T[i] = 0; + zend_bitset_excl(taken_T, i); } else { /* Code which gets here is using a wrongly built opcode such as RECV() */ map_T[currT] = i; - valid_T[currT] = 1; + zend_bitset_incl(valid_T, currT); } ZEND_RESULT(opline).var = NUM_VAR(i + offset); } } if (var_to_free >= 0) { - taken_T[var_to_free] = 0; + zend_bitset_excl(taken_T, var_to_free); var_to_free = -1; }