From: Dmitry Stogov Date: Wed, 18 Jun 2014 13:09:37 +0000 (+0400) Subject: Use arena allocator for optimizer temporary data structures X-Git-Tag: POST_PHPNG_MERGE~180^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4f38192ecbbc7ece3a6070b8bac4468e890f476;p=php Use arena allocator for optimizer temporary data structures --- diff --git a/Zend/zend_arena.h b/Zend/zend_arena.h index 68fb660bbb..69ac6687ef 100644 --- a/Zend/zend_arena.h +++ b/Zend/zend_arena.h @@ -78,17 +78,35 @@ static zend_always_inline void* zend_arena_alloc(zend_arena **arena_ptr, size_t return (void*) ptr; } -static zend_always_inline void* zend_arena_calloc(zend_arena **arena_ptr, size_t unit_size, size_t count) +static zend_always_inline void* zend_arena_calloc(zend_arena **arena_ptr, size_t count, size_t unit_size) { - size_t size = ZEND_MM_ALIGNED_SIZE(unit_size) * count; + size_t size = unit_size * count; void *ret; - ZEND_ASSERT(size > ZEND_MM_ALIGNED_SIZE(unit_size) && size > count); + ZEND_ASSERT(size >= unit_size && size >= count); ret = zend_arena_alloc(arena_ptr, size); memset(ret, 0, size); return ret; } +static zend_always_inline void* zend_arena_checkpoint(zend_arena *arena) +{ + return arena->ptr; +} + +static zend_always_inline void zend_arena_release(zend_arena **arena_ptr, void *checkpoint) +{ + zend_arena *arena = *arena_ptr; + + while (UNEXPECTED((char*)checkpoint > arena->end) || + UNEXPECTED((char*)checkpoint < (char*)arena)) { + zend_arena *prev = arena->prev; + efree(arena); + *arena_ptr = arena = prev; + } + arena->ptr = (char*)checkpoint; +} + #endif /* _ZEND_ARENA_H_ */ /* diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 20b7a1ae31..7df2764d93 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -80,7 +80,7 @@ static inline void print_block(zend_code_block *block, zend_op *opcodes, char *t /* find code blocks in op_array code block is a set of opcodes with single flow of control, i.e. without jmps, branches, etc. */ -static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) +static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimizer_ctx *ctx) { zend_op *opline; zend_op *end = op_array->opcodes + op_array->last; @@ -88,7 +88,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) zend_uint opno = 0; memset(cfg, 0, sizeof(zend_cfg)); - blocks = cfg->blocks = ecalloc(op_array->last + 2, sizeof(zend_code_block)); + blocks = cfg->blocks = zend_arena_calloc(&ctx->arena, op_array->last + 2, sizeof(zend_code_block)); opline = op_array->opcodes; blocks[0].start_opline = opline; blocks[0].start_opline_no = 0; @@ -102,7 +102,6 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) /* would not optimize non-optimized BRK/CONTs - we cannot really know where it jumps, so these optimizations are too dangerous */ - efree(blocks); return 0; #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO case ZEND_FAST_CALL: @@ -169,8 +168,8 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) /* first find block start points */ if (op_array->last_try_catch) { int i; - cfg->try = ecalloc(op_array->last_try_catch, sizeof(zend_code_block *)); - cfg->catch = ecalloc(op_array->last_try_catch, sizeof(zend_code_block *)); + cfg->try = zend_arena_calloc(&ctx->arena, op_array->last_try_catch, sizeof(zend_code_block *)); + cfg->catch = zend_arena_calloc(&ctx->arena, op_array->last_try_catch, sizeof(zend_code_block *)); for (i = 0; i< op_array->last_try_catch; i++) { cfg->try[i] = &blocks[op_array->try_catch_array[i].try_op]; cfg->catch[i] = &blocks[op_array->try_catch_array[i].catch_op]; @@ -203,9 +202,9 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) } } if (j) { - cfg->loop_start = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *)); - cfg->loop_cont = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *)); - cfg->loop_brk = ecalloc(op_array->last_brk_cont, sizeof(zend_code_block *)); + cfg->loop_start = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); + cfg->loop_cont = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); + cfg->loop_brk = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); j = 0; for (i = 0; i< op_array->last_brk_cont; i++) { if (op_array->brk_cont_array[i].start >= 0 && @@ -317,18 +316,16 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg) zend_block_source *__s = tob->sources; \ while (__s && __s->from != fromb) __s = __s->next; \ if (__s == NULL) { \ - zend_block_source *__t = emalloc(sizeof(zend_block_source)); \ + zend_block_source *__t = zend_arena_alloc(&ctx->arena, sizeof(zend_block_source)); \ __t->next = tob->sources; \ tob->sources = __t; \ __t->from = fromb; \ } \ } -#define DEL_SOURCE(cs) { \ - zend_block_source *__ns = (*cs)->next; \ - efree(*cs); \ - *cs = __ns; \ -} +#define DEL_SOURCE(cs) do { \ + *(cs) = (*(cs))->next; \ + } while (0) static inline void replace_source(zend_block_source *list, zend_code_block *old, zend_code_block *new) @@ -400,7 +397,7 @@ static inline void del_source(zend_code_block *from, zend_code_block *to) /* move 'to'`s references to 'from' */ to->start_opline = NULL; to->access = 0; - efree(to->sources); +//???A efree(to->sources); to->sources = NULL; from_block->follow_to = to->follow_to; if (to->op1_to) { @@ -423,7 +420,7 @@ static inline void del_source(zend_code_block *from, zend_code_block *to) } } -static void delete_code_block(zend_code_block *block) +static void delete_code_block(zend_code_block *block, zend_optimizer_ctx *ctx) { if (block->protected) { return; @@ -455,7 +452,7 @@ static void delete_code_block(zend_code_block *block) block->access = 0; } -static void zend_access_path(zend_code_block *block) +static void zend_access_path(zend_code_block *block, zend_optimizer_ctx *ctx) { if (block->access) { return; @@ -463,25 +460,25 @@ static void zend_access_path(zend_code_block *block) block->access = 1; if (block->op1_to) { - zend_access_path(block->op1_to); + zend_access_path(block->op1_to, ctx); ADD_SOURCE(block, block->op1_to); } if (block->op2_to) { - zend_access_path(block->op2_to); + zend_access_path(block->op2_to, ctx); ADD_SOURCE(block, block->op2_to); } if (block->ext_to) { - zend_access_path(block->ext_to); + zend_access_path(block->ext_to, ctx); ADD_SOURCE(block, block->ext_to); } if (block->follow_to) { - zend_access_path(block->follow_to); + zend_access_path(block->follow_to, ctx); ADD_SOURCE(block, block->follow_to); } } /* Traverse CFG, mark reachable basic blocks and build back references */ -static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int find_start) +static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int find_start, zend_optimizer_ctx *ctx) { zend_code_block *blocks = cfg->blocks; zend_code_block *start = find_start? NULL : blocks; @@ -495,26 +492,26 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int start = b; } b->access = 0; - cs = b->sources; - while (cs) { - zend_block_source *n = cs->next; - efree(cs); - cs = n; - } +//???A cs = b->sources; +//???A while (cs) { +//???A zend_block_source *n = cs->next; +//???A efree(cs); +//???A cs = n; +//???A } b->sources = NULL; b = b->next; } /* Walk thorough all paths */ - zend_access_path(start); + zend_access_path(start, ctx); /* Add brk/cont paths */ if (op_array->last_brk_cont) { int i; for (i=0; i< op_array->last_brk_cont; i++) { - zend_access_path(cfg->loop_start[i]); - zend_access_path(cfg->loop_cont[i]); - zend_access_path(cfg->loop_brk[i]); + zend_access_path(cfg->loop_start[i], ctx); + zend_access_path(cfg->loop_cont[i], ctx); + zend_access_path(cfg->loop_brk[i], ctx); } } @@ -523,7 +520,7 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int int i; for (i=0; i< op_array->last_try_catch; i++) { if (!cfg->catch[i]->access) { - zend_access_path(cfg->catch[i]); + zend_access_path(cfg->catch[i], ctx); } } } @@ -558,7 +555,7 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int convert_to_string((v)); \ } -static void strip_nop(zend_code_block *block) +static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx) { zend_op *opline = block->start_opline; zend_op *end, *new_end; @@ -568,7 +565,7 @@ static void strip_nop(zend_code_block *block) if (block->len == 1) { /* this block is all NOPs, join with following block */ if (block->follow_to) { - delete_code_block(block); + delete_code_block(block, ctx); } return; } @@ -603,11 +600,11 @@ static void strip_nop(zend_code_block *block) block->len = new_end - block->start_opline; } -static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, char *used_ext TSRMLS_DC) +static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, char *used_ext, zend_cfg *cfg, zend_optimizer_ctx *ctx TSRMLS_DC) { zend_op *opline = block->start_opline; zend_op *end, *last_op = NULL; - zend_op **Tsource = NULL; + zend_op **Tsource = cfg->Tsource; print_block(block, op_array->opcodes, "Opt "); @@ -616,7 +613,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, if (block->len == 1) { /* this block is all NOPs, join with following block */ if (block->follow_to) { - delete_code_block(block); + delete_code_block(block, ctx); } return; } @@ -626,9 +623,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, } /* we track data dependencies only insight a single basic block */ - if (op_array->T) { - Tsource = ecalloc(op_array->last_var + op_array->T, sizeof(zend_op *)); - } + memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *)); opline = block->start_opline; end = opline + block->len; while ((op_array->T) && (opline < end)) { @@ -1198,11 +1193,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline++; } - strip_nop(block); - - if (op_array->T) { - efree(Tsource); - } + strip_nop(block, ctx); } /* Rebuild plain (optimized) op_array from CFG */ @@ -1277,8 +1268,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) } } op_array->last_try_catch = j; - efree(cfg->try); - efree(cfg->catch); } /* adjust loop jump targets */ @@ -1289,9 +1278,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) op_array->brk_cont_array[i].cont = cfg->loop_cont[i]->start_opline - new_opcodes; op_array->brk_cont_array[i].brk = cfg->loop_brk[i]->start_opline - new_opcodes; } - efree(cfg->loop_start); - efree(cfg->loop_cont); - efree(cfg->loop_brk); } /* adjust jump targets */ @@ -1337,7 +1323,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) #endif } -static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_array, zend_code_block *blocks TSRMLS_DC) +static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_array, zend_code_block *blocks, zend_cfg *cfg, zend_optimizer_ctx *ctx TSRMLS_DC) { /* last_op is the last opcode of the current block */ zend_op *last_op = (block->start_opline + block->len - 1); @@ -1364,7 +1350,7 @@ static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_arra block->len--; if (block->len == 0) { /* this block is nothing but NOP now */ - delete_code_block(block); + delete_code_block(block, ctx); } break; } @@ -1473,7 +1459,7 @@ static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_arra block->len--; if(block->len == 0) { /* this block is nothing but NOP now */ - delete_code_block(block); + delete_code_block(block, ctx); } break; } @@ -1665,10 +1651,8 @@ next_target: if (var_num <= 0) { return; } - same_t = ecalloc(var_num, sizeof(char)); - if (same_t == NULL) { - return; - } + same_t = cfg->same_t; + memset(same_t, 0, var_num); same_t[VAR_NUM_EX(last_op->op1)] |= ZEND_OP1_TYPE(last_op); same_t[VAR_NUM_EX(last_op->result)] |= ZEND_RESULT_TYPE(last_op); target_block = block->op2_to; @@ -1742,9 +1726,6 @@ next_target_ex: } ADD_SOURCE(block, block->op2_to); } - if (same_t != NULL) { - efree(same_t); - } } break; @@ -1895,19 +1876,22 @@ next_target_znz: /* 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) +static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *used_ext, zend_optimizer_ctx *ctx) { zend_code_block *next_block = block->next; char *usage; char *defined_here; + void *checkpoint; if (op_array->T == 0) { /* shortcut - if no Ts, nothing to do */ return; } - usage = ecalloc(op_array->last_var + op_array->T, 1); - defined_here = emalloc(op_array->last_var + op_array->T); + 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); while (next_block) { zend_op *opline = next_block->start_opline; @@ -2053,18 +2037,18 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * block = block->next; } /* end blocks */ - efree(defined_here); - efree(usage); + zend_arena_release(&ctx->arena, checkpoint); } #define PASSES 3 -static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC) +static void zend_block_optimization(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRMLS_DC) { zend_cfg cfg; zend_code_block *cur_block; int pass; char *usage; + void *checkpoint; #if DEBUG_BLOCKPASS fprintf(stderr, "File %s func %s\n", op_array->filename, op_array->function_name? op_array->function_name : "main"); @@ -2078,24 +2062,34 @@ static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC) #endif /* Build CFG */ - if (!find_code_blocks(op_array, &cfg)) { + checkpoint = zend_arena_checkpoint(ctx->arena); + if (!find_code_blocks(op_array, &cfg, ctx)) { + zend_arena_release(&ctx->arena, checkpoint); return; } - zend_rebuild_access_path(&cfg, op_array, 0); + zend_rebuild_access_path(&cfg, op_array, 0, ctx); /* full rebuild here to produce correct sources! */ - usage = emalloc(op_array->last_var + op_array->T); + if (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); + } else { + 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_t_usage(cfg.blocks, op_array, usage); + zend_t_usage(cfg.blocks, op_array, usage, ctx); /* optimize each basic block separately */ for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) { if (!cur_block->access) { continue; } - zend_optimize_block(cur_block, op_array, usage TSRMLS_CC); + zend_optimize_block(cur_block, op_array, usage, &cfg, ctx TSRMLS_CC); } /* Jump optimization for each block */ @@ -2103,19 +2097,19 @@ static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC) if (!cur_block->access) { continue; } - zend_jmp_optimization(cur_block, op_array, cfg.blocks TSRMLS_CC); + zend_jmp_optimization(cur_block, op_array, cfg.blocks, &cfg, ctx TSRMLS_CC); } /* Eliminate unreachable basic blocks */ - zend_rebuild_access_path(&cfg, op_array, 1); + zend_rebuild_access_path(&cfg, op_array, 1, ctx); } memset(usage, 0, op_array->last_var + op_array->T); - zend_t_usage(cfg.blocks, op_array, usage); + zend_t_usage(cfg.blocks, op_array, usage, ctx); assemble_code_blocks(&cfg, op_array); - efree(usage); /* Destroy CFG */ +/* ???A for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) { zend_block_source *cs = cur_block->sources; while (cs) { @@ -2124,5 +2118,6 @@ static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC) cs = n; } } - efree(cfg.blocks); +*/ + zend_arena_release(&ctx->arena, checkpoint); } diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index aad6243e0a..6300d0fcfd 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -87,7 +87,7 @@ static void optimizer_literal_class_info(literal_info *info, } } -static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC) +static void optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRMLS_DC) { zend_op *opline, *end; int i, j, n, *map, cache_slots; @@ -98,9 +98,10 @@ static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC) int l_true = -1; HashTable hash; zend_string *key = NULL; + void *checkpoint = zend_arena_checkpoint(ctx->arena); if (op_array->last_literal) { - info = (literal_info*)ecalloc(op_array->last_literal, sizeof(literal_info)); + info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info)); /* Mark literals of specific types */ opline = op_array->opcodes; @@ -282,7 +283,9 @@ static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC) /* Merge equal constants */ j = 0; cache_slots = 0; zend_hash_init(&hash, 16, NULL, NULL, 0); - map = (int*)ecalloc(op_array->last_literal, sizeof(int)); + map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int)); +//???A +memset(map, 0, op_array->last_literal * sizeof(int)); for (i = 0; i < op_array->last_literal; i++) { if (!info[i].flags) { /* unsed literal */ @@ -440,8 +443,7 @@ static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC) } opline++; } - efree(map); - efree(info); + zend_arena_release(&ctx->arena, checkpoint); #if DEBUG_COMPACT_LITERALS { diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index f9ae14290f..cd27704de5 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -8,16 +8,12 @@ typedef struct _optimizer_call_info { zend_op *opline; } optimizer_call_info; -static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script *script TSRMLS_DC) { +static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRMLS_DC) { zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; int call = 0; -#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO - optimizer_call_info *call_stack = ecalloc(op_array->nested_calls + 1, sizeof(optimizer_call_info)); -#else - int stack_size = 4; - optimizer_call_info *call_stack = ecalloc(stack_size, sizeof(optimizer_call_info)); -#endif + void *checkpoint = zend_arena_checkpoint(ctx->arena); + optimizer_call_info *call_stack = zend_arena_calloc(&ctx->arena, op_array->nested_calls + 1, sizeof(optimizer_call_info)); while (opline < end) { switch (opline->opcode) { @@ -26,7 +22,7 @@ static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script if (ZEND_OP2_TYPE(opline) == IS_CONST) { zend_function *func; zval *function_name = &op_array->literals[opline->op2.constant + 1]; - if ((func = zend_hash_find_ptr(&script->function_table, + if ((func = zend_hash_find_ptr(&ctx->script->function_table, Z_STR_P(function_name))) != NULL) { call_stack[call].func = func; } @@ -37,13 +33,6 @@ static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script case ZEND_INIT_STATIC_METHOD_CALL: call_stack[call].opline = opline; call++; -#if ZEND_EXTENSION_API_NO < PHP_5_5_X_API_NO - if (call == stack_size) { - stack_size += 4; - call_stack = erealloc(call_stack, sizeof(optimizer_call_info) * stack_size); - memset(call_stack + 4, 0, 4 * sizeof(optimizer_call_info)); - } -#endif break; case ZEND_DO_FCALL_BY_NAME: call--; @@ -137,6 +126,6 @@ static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script opline++; } - efree(call_stack); + zend_arena_release(&ctx->arena, checkpoint); } #endif diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c index 77e07a586e..af193802dd 100644 --- a/ext/opcache/Optimizer/optimize_temp_vars_5.c +++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c @@ -70,7 +70,7 @@ static const char op_const_means_class[256] = { max = i; \ } -static void optimize_temporary_variables(zend_op_array *op_array) +static void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; @@ -83,11 +83,12 @@ static void optimize_temporary_variables(zend_op_array *op_array) int i; int max = -1; int var_to_free = -1; + void *checkpoint = zend_arena_checkpoint(ctx->arena); - taken_T = (char *) emalloc(T); - start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *)); - valid_T = (char *) emalloc(T); - map_T = (int *) emalloc(T * sizeof(int)); + taken_T = (char *) zend_arena_alloc(&ctx->arena, T); + start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); + valid_T = (char *) zend_arena_alloc(&ctx->arena, T); + map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; @@ -238,9 +239,6 @@ static void optimize_temporary_variables(zend_op_array *op_array) opline--; } - efree(taken_T); - efree(start_of_T); - efree(valid_T); - efree(map_T); + zend_arena_release(&ctx->arena, checkpoint); op_array->T = max + 1; } diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index ab41fa92f7..73fa0d02f9 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -16,7 +16,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { int i = 0; zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; - zend_bool collect_constants = (op_array == &script->main_op_array); + zend_bool collect_constants = (op_array == &ctx->script->main_op_array); while (opline < end) { switch (opline->opcode) { @@ -245,7 +245,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { zval c; if (!zend_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) { - if (!*constants || !zend_optimizer_get_collected_constant(*constants, &ZEND_OP2_LITERAL(opline), &c)) { + if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) { break; } } @@ -334,7 +334,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { (opline-2)->opcode == ZEND_SEND_VAL && ZEND_OP1_TYPE(opline-2) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) { - zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1)); + zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1)); break; } else { /* don't colllect constants after any other function call */ @@ -452,7 +452,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { if (collect_constants && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) { - zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); + zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); } break; #endif diff --git a/ext/opcache/Optimizer/pass5.c b/ext/opcache/Optimizer/pass5.c index b0d651a5fc..ba36da5990 100644 --- a/ext/opcache/Optimizer/pass5.c +++ b/ext/opcache/Optimizer/pass5.c @@ -1,3 +1,3 @@ if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) { - zend_block_optimization(op_array TSRMLS_CC); + zend_block_optimization(op_array, ctx TSRMLS_CC); } diff --git a/ext/opcache/Optimizer/pass9.c b/ext/opcache/Optimizer/pass9.c index 586160c14d..ec54dc6c1d 100644 --- a/ext/opcache/Optimizer/pass9.c +++ b/ext/opcache/Optimizer/pass9.c @@ -4,5 +4,5 @@ */ if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) { - optimize_temporary_variables(op_array); + optimize_temporary_variables(op_array, ctx); } diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 029f0846dd..2ea6544e23 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -35,16 +35,16 @@ static void zend_optimizer_zval_dtor_wrapper(zval *zvalue) zval_dtor(zvalue); } -static void zend_optimizer_collect_constant(HashTable **constants, zval *name, zval* value) +static void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value) { zval val; - if (!*constants) { - *constants = emalloc(sizeof(HashTable)); - zend_hash_init(*constants, 16, NULL, zend_optimizer_zval_dtor_wrapper, 0); + if (!ctx->constants) { + ctx->constants = zend_arena_alloc(&ctx->arena, sizeof(HashTable)); + zend_hash_init(ctx->constants, 16, NULL, zend_optimizer_zval_dtor_wrapper, 0); } ZVAL_DUP(&val, value); - zend_hash_add(*constants, Z_STR_P(name), &val); + zend_hash_add(ctx->constants, Z_STR_P(name), &val); } static int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value) @@ -425,9 +425,8 @@ static void replace_tmp_by_const(zend_op_array *op_array, #include "Optimizer/compact_literals.c" #include "Optimizer/optimize_func_calls.c" -static void zend_optimize(zend_op_array *op_array, - zend_persistent_script *script, - HashTable **constants TSRMLS_DC) +static void zend_optimize(zend_op_array *op_array, + zend_optimizer_ctx *ctx TSRMLS_DC) { if (op_array->type == ZEND_EVAL_CODE || (op_array->fn_flags & ZEND_ACC_INTERACTIVE)) { @@ -462,7 +461,7 @@ static void zend_optimize(zend_op_array *op_array, * - INIT_FCALL_BY_NAME -> DO_FCALL */ if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) { - optimize_func_calls(op_array, script TSRMLS_CC); + optimize_func_calls(op_array, ctx TSRMLS_CC); } #endif @@ -486,14 +485,13 @@ static void zend_optimize(zend_op_array *op_array, * - Compact literals table */ if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) { - optimizer_compact_literals(op_array TSRMLS_CC); + optimizer_compact_literals(op_array, ctx TSRMLS_CC); } #endif } -static void zend_accel_optimize(zend_op_array *op_array, - zend_persistent_script *script, - HashTable **constants TSRMLS_DC) +static void zend_accel_optimize(zend_op_array *op_array, + zend_optimizer_ctx *ctx TSRMLS_DC) { zend_op *opline, *end; @@ -543,7 +541,7 @@ static void zend_accel_optimize(zend_op_array *op_array, } /* Do actual optimizations */ - zend_optimize(op_array, script, constants TSRMLS_CC); + zend_optimize(op_array, ctx TSRMLS_CC); /* Redo pass_two() */ opline = op_array->opcodes; @@ -596,17 +594,21 @@ int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC) { uint idx, j; Bucket *p, *q; - HashTable *constants = NULL; zend_class_entry *ce; zend_op_array *op_array; + zend_optimizer_ctx ctx; - zend_accel_optimize(&script->main_op_array, script, &constants TSRMLS_CC); + ctx.arena = zend_arena_create(64 * 1024); + ctx.script = script; + ctx.constants = NULL; + + zend_accel_optimize(&script->main_op_array, &ctx TSRMLS_CC); for (idx = 0; idx < script->function_table.nNumUsed; idx++) { p = script->function_table.arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; op_array = (zend_op_array*)Z_PTR(p->val); - zend_accel_optimize(op_array, script, &constants TSRMLS_CC); + zend_accel_optimize(op_array, &ctx TSRMLS_CC); } for (idx = 0; idx < script->class_table.nNumUsed; idx++) { @@ -618,7 +620,7 @@ int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC) if (Z_TYPE(q->val) == IS_UNDEF) continue; op_array = (zend_op_array*)Z_PTR(q->val); if (op_array->scope == ce) { - zend_accel_optimize(op_array, script, &constants TSRMLS_CC); + zend_accel_optimize(op_array, &ctx TSRMLS_CC); } else if (op_array->type == ZEND_USER_FUNCTION) { zend_op_array *orig_op_array; if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, q->key)) != NULL) { @@ -630,10 +632,10 @@ int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC) } } - if (constants) { - zend_hash_destroy(constants); - efree(constants); + if (ctx.constants) { + zend_hash_destroy(ctx.constants); } + zend_arena_destroy(ctx.arena); return 1; } diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 049036c1f4..0ae3feb2ee 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -55,6 +55,12 @@ # define SAME_VAR(op1, op2) (((op1.op_type == IS_VAR && op2.op_type == IS_VAR) || (op1.op_type == IS_TMP_VAR && op2.op_type == IS_TMP_VAR)) && op1.u.var == op2.u.var) #endif +typedef struct _zend_optimizer_ctx { + zend_arena *arena; + zend_persistent_script *script; + HashTable *constants; +} zend_optimizer_ctx; + typedef struct _zend_code_block zend_code_block; typedef struct _zend_block_source zend_block_source; @@ -79,6 +85,8 @@ typedef struct _zend_cfg { zend_code_block **loop_start; zend_code_block **loop_cont; zend_code_block **loop_brk; + zend_op **Tsource; + char *same_t; } zend_cfg; struct _zend_block_source {