mirror of
https://github.com/php/php-src.git
synced 2024-11-24 02:15:04 +08:00
Reduce memory usage by using bitsets instead of array of bytes.
This commit is contained in:
parent
6d681876ee
commit
90cb3bb7de
185
Zend/zend_bitset.h
Normal file
185
Zend/zend_bitset.h
Normal file
@ -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 <dmitry@zend.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $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:
|
||||
*/
|
@ -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 (opline<end) {
|
||||
T_USAGE(opline->op1);
|
||||
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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user