/* 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;
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;
/* 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:
/* 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];
}
}
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 &&
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)
/* 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) {
}
}
-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;
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;
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;
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);
}
}
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);
}
}
}
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;
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;
}
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 ");
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;
}
}
/* 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)) {
opline++;
}
- strip_nop(block);
-
- if (op_array->T) {
- efree(Tsource);
- }
+ strip_nop(block, ctx);
}
/* Rebuild plain (optimized) op_array from CFG */
}
}
op_array->last_try_catch = j;
- efree(cfg->try);
- efree(cfg->catch);
}
/* adjust loop jump targets */
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 */
#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);
block->len--;
if (block->len == 0) {
/* this block is nothing but NOP now */
- delete_code_block(block);
+ delete_code_block(block, ctx);
}
break;
}
block->len--;
if(block->len == 0) {
/* this block is nothing but NOP now */
- delete_code_block(block);
+ delete_code_block(block, ctx);
}
break;
}
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;
}
ADD_SOURCE(block, block->op2_to);
}
- if (same_t != NULL) {
- efree(same_t);
- }
}
break;
/* 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;
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");
#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 */
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) {
cs = n;
}
}
- efree(cfg.blocks);
+*/
+ zend_arena_release(&ctx->arena, checkpoint);
}
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)
#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)) {
* - 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
* - 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;
}
/* 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;
{
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++) {
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) {
}
}
- if (constants) {
- zend_hash_destroy(constants);
- efree(constants);
+ if (ctx.constants) {
+ zend_hash_destroy(ctx.constants);
}
+ zend_arena_destroy(ctx.arena);
return 1;
}