cvs: pear /PECL/optimizer Makefile.in config.m4 debug.php optimizer.h optimizer_compile.c optimizer_compile.h optimizer_debug.c optimizer_debug.h
optimizer_instructions.c optimizer_instructions.h optimizer_main.c optimizer_main.h optimizer_newopcodes.h optimizer_pair.c optimizer_pair.h
optimizer_zend_util.c optimizer_zend_util.h php_optimizer.c php_optimizer.h zend.patch

From: Date: Mon, 04 Nov 2002 23:46:20 +0000
Subject: cvs: pear /PECL/optimizer Makefile.in config.m4 debug.php optimizer.h optimizer_compile.c optimizer_compile.h optimizer_debug.c optimizer_debug.h
optimizer_instructions.c optimizer_instructions.h optimizer_main.c optimizer_main.h optimizer_newopcodes.h optimizer_pair.c optimizer_pair.h
optimizer_zend_util.c optimizer_zend_util.h php_optimizer.c php_optimizer.h zend.patch
Groups: php.pear.cvs 
Request: Send a blank email to pear-cvs+get-7287@lists.php.net to get a copy of this message
gschlossnagle Mon Nov 4 18:46:20 2002 EDT Added files: /pear/PECL/optimizer Makefile.in config.m4 debug.php optimizer.h optimizer_compile.c optimizer_compile.h optimizer_debug.c optimizer_debug.h optimizer_instructions.c optimizer_instructions.h optimizer_main.c optimizer_main.h optimizer_newopcodes.h optimizer_pair.c optimizer_pair.h optimizer_zend_util.c optimizer_zend_util.h php_optimizer.c php_optimizer.h zend.patch Log: initial inport into PECL!

Index: pear/PECL/optimizer/Makefile.in +++ pear/PECL/optimizer/Makefile.in # # $Id: Makefile.in,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ # LTLIBRARY_NAME = liboptimizer.la LTLIBRARY_SOURCES = optimizer_compile.c optimizer_debug.c optimizer_instructions.c optimizer_main.c optimizer_pair.c optimizer_zend_util.c php_optimizer.c LTLIBRARY_SHARED_NAME = php_optimizer.la LTLIBRARY_SHARED_LIBADD = $(OPC_LIBADD) include $(top_srcdir)/build/dynlib.mk Index: pear/PECL/optimizer/config.m4 +++ pear/PECL/optimizer/config.m4 dnl dnl $Id: config.m4,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ dnl PHP_ARG_WITH(opc,for OPC support, [ --without-optimizer do not include OPC support [default=yes]],yes) if test "$PHP_OPTIMIZER" != "no"; then PHP_EXTENSION(optimizer, $ext_shared) AC_DEFINE(HAVE_OPTIMIZER, 1, [ ]) fi Index: pear/PECL/optimizer/debug.php +++ pear/PECL/optimizer/debug.php <? $x = optimizer_debug_compile($argv[1]); foreach ($x['op_array']['opcodes'] as $op) { printf("%04d: %s\n", $op['op_num'], $op['assembly']); } ?> Index: pear/PECL/optimizer/optimizer.h +++ pear/PECL/optimizer/optimizer.h /* $Id: optimizer.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_H #define OPC_H /* Required PHP headers. */ #include "php.h" /* Required Zend headers. */ #include "zend.h" #include "zend_API.h" #include "zend_compile.h" #include "zend_hash.h" /* Commonly needed C library headers. */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_compile.c +++ pear/PECL/optimizer/optimizer_compile.c /* $Id: optimizer_compile.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "optimizer_main.h" #include "optimizer.h" #include "optimizer_zend_util.h" #include "optimizer_pair.h" #include <assert.h> /* {{{ rewrite helper functions */ /* cleans up and deallocates a znode */ static void clear_znode(znode* n) { if (n->op_type == IS_CONST) { zval_dtor(&n->u.constant); } SET_UNUSED(*n); } /* overwrites dst with contents of src, clears src */ static move_znode(znode* dst, znode* src) { memcpy(dst, src, sizeof(znode)); SET_UNUSED(*src); } /* cleans up and deallocates a zend_op */ static void clear_zend_op(zend_op* op) { op->opcode = ZEND_NOP; clear_znode(&op->result); clear_znode(&op->op1); clear_znode(&op->op2); } /* overwrites dst with contents of src, clears src */ static void move_zend_op(zend_op* dst, zend_op* src) { clear_zend_op(dst); dst->opcode = src->opcode; src->opcode = ZEND_NOP; dst->extended_value = src->extended_value; dst->lineno = src->lineno; move_znode(&dst->result, &src->result); move_znode(&dst->op1, &src->op1); move_znode(&dst->op2, &src->op2); } /* op is a branch instruction that branches to old, change it to new */ static void change_branch_target(zend_op* op, int old, int new) { switch (op->opcode) { case ZEND_JMP: assert(op->op1.u.opline_num == old); op->op1.u.opline_num = new; break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMP_NO_CTOR: assert(op->op2.u.opline_num == old); op->op2.u.opline_num = new; break; case ZEND_JMPZNZ: if (op->op2.u.opline_num == old) { op->op2.u.opline_num = new; } else if (op->extended_value == old) { op->extended_value = new; } else { assert(0); } break; default: assert(0); } } /* returns true if opcode is a branch instruction */ static int is_branch_op(int opcode) { switch (opcode) { case ZEND_JMP: case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMP_NO_CTOR: case ZEND_JMPZNZ: return 1; } return 0; } /* squeezes no-ops out of the zend_op array */ static int compress_ops(zend_op* ops, Pair** jumps, int num_ops) { int i, j, k; for (i = 0, j = 0; j < num_ops; i++, j++) { if (ops[i].opcode == ZEND_NOP) { Pair* branches; /* search for a non-noop op, updating branch targets as we go */ for (;;) { /* update branch targets */ for (branches = jumps[j]; branches; branches = cdr(branches)) { change_branch_target(&ops[car(branches)], j, i); } /* quit when we've found a non-noop instruction */ if (ops[j].opcode != ZEND_NOP) { break; } j++; } /* update jump table IFF ops[j] is a branch */ if (is_branch_op(ops[j].opcode)) { int x; for (x = 0; x < num_ops; x++) { Pair* p = jumps[x]; for (; p; p = cdr(p)) { if (car(p) == j) { pair_set_car(p, i); } } } } move_zend_op(ops + i, ops + j); } } while (--j > i) { clear_zend_op(ops + j); } return i; } /* op must be 'pure' and have two constant operands; returns its value */ static zval* compute_result_of_constant_op(zend_op* op) { zval* result = 0; int (*binary_op)(zval*, zval*, zval* TSRMLS_DC) = 0; // TODO: add cases for other deterministic binary ops! // TODO: extend to this work with the few unary ops switch (op->opcode) { case ZEND_ADD: binary_op = add_function; break; case ZEND_SUB: binary_op = sub_function; break; case ZEND_MUL: binary_op = mul_function; break; case ZEND_DIV: binary_op = div_function; break; case ZEND_MOD: binary_op = mod_function; break; case ZEND_SL: binary_op = shift_left_function; break; case ZEND_SR: binary_op = shift_right_function; break; case ZEND_CONCAT: binary_op = concat_function; break; } if (binary_op) { ALLOC_INIT_ZVAL(result); binary_op(result, &op->op1.u.constant, &op->op2.u.constant); return result; } assert(0); /* no function found */ } /* }}} */ /* {{{ rewrite functions */ static void rewrite_constant_op(zend_op* ops, Pair* p) { zend_op* op; zval* result; assert(pair_length(p) == 1); // DARG_LOAD_CONSTANT takes two operands -- the result temporary (in // result), and the constant (in op1) op = ops + car(p); result = compute_result_of_constant_op(op); op->opcode = DARG_LOAD_CONSTANT; clear_znode(&op->op1); clear_znode(&op->op2); op->extended_value = 0; op->op1.op_type = IS_CONST; op->op1.u.constant = *result; zval_copy_ctor(&op->op1.u.constant); } static void rewrite_constant_expr(zend_op* ops, Pair* p) { zend_op* op; zval* result; // DARG_LOAD_CONSTANT takes two operands -- the result temporary (in // result), and the constant (in op1) if (pair_length(p) == 3) { op = ops + caddr(p); clear_znode(&op->op1); move_znode (&op->op1, &ops[car(p)].op1); clear_znode(&op->op2); move_znode (&op->op2, &ops[cadr(p)].op1); result = compute_result_of_constant_op(op); op->opcode = DARG_LOAD_CONSTANT; op->op1.op_type = IS_CONST; op->op1.u.constant = *result; zval_copy_ctor(&op->op1.u.constant); clear_znode(&op->op2); clear_zend_op(ops + car(p)); // don't need this anymore clear_zend_op(ops + cadr(p)); // don't need this anymore } else if (pair_length(p) == 2) { op = ops + cadr(p); clear_znode(&op->op1); move_znode (&op->op1, &ops[car(p)].op1); result = compute_result_of_constant_op(op); op->opcode = DARG_LOAD_CONSTANT; op->op1.op_type = IS_CONST; op->op1.u.constant = *result; zval_copy_ctor(&op->op1.u.constant); clear_znode(&op->op2); clear_zend_op(ops + car(p)); // don't need this anymore } else { assert(0); /* expected to rewrite 2 or 3 ops */ } } static void rewrite_inc(zend_op* ops, Pair* p) { assert(pair_length(p) == 3); // DARG_INC_VAR takes one operand (in op1) -- the variable name ops[car(p)].opcode = DARG_INCDEC_VAR; move_znode(&ops[car(p)].result, &ops[cadr(p)].result); ops[car(p)].op2.u.fetch_type = ops[cadr(p)].opcode; clear_zend_op(&ops[cadr(p)]); // don't need this anymore clear_zend_op(&ops[caddr(p)]); // don't need this anymore } static void rewrite_add_string(zend_op* ops, Pair* p) { int curr = car(p); assert(pair_length(p) >= 2); for (p = cdr(p); p; p = cdr(p)) { concat_function(&ops[car(p)].op2.u.constant, &ops[car(p)].op2.u.constant, &ops[curr].op2.u.constant); clear_zend_op(ops + curr); curr = car(p); } } /* }}} */ /* {{{ peephole helper functions */ /* scans for the next opcode, skipping no-ops */ static int next_op(zend_op* ops, int i, int num_ops) { while (++i < num_ops) { if (ops[i].opcode != ZEND_NOP && ops[i].opcode != ZEND_EXT_NOP) { break; } } return i; } /* returns list of potential branch targets for this op */ static Pair* extract_branch_targets(zend_op* op) { switch (op->opcode) { case ZEND_JMP: return cons(op->op1.u.opline_num, 0); case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMP_NO_CTOR: return cons(op->op2.u.opline_num, 0); case ZEND_JMPZNZ: return cons(op->op2.u.opline_num, cons(op->extended_value, 0)); } return 0; } /* retval[i] -> list of instruction indices that may branch to i */ static Pair** build_jump_array(zend_op* ops, int num_ops) { Pair** jumps; int i; jumps = (Pair**) malloc(num_ops * sizeof(Pair*)); memset(jumps, 0, num_ops * sizeof(Pair*)); for (i = 0; i < num_ops; i++) { Pair* targets = extract_branch_targets(&ops[i]); while (targets) { jumps[car(targets)] = cons(i, jumps[car(targets)]); targets = cdr(targets); } } return jumps; } /* deallocates structure created by build_jump_array */ static void destroy_jump_array(Pair** p, int num_ops) { int i; for (i = 0; i < num_ops; i++) { pair_destroy(p[i]); } free(p); } /* returns true if any of the indices in 'ops' are targets of a branch */ static int are_branch_targets(Pair* ops, Pair** jumps) { return ops ? jumps[car(ops)] ? 1 : are_branch_targets(cdr(ops), jumps) : 0; } /* returns true if op is 'pure' and all its operands are constants */ static int is_constant_op(zend_op* op) { switch (op->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: return op->op1.op_type == IS_CONST && op->op2.op_type == IS_CONST; } return 0; } /* returns true if op is a deterministic binary instr. */ static int is_pure_binary_op(zend_op* op) { switch (op->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: return 1; } return 0; } /* }}} */ /* {{{ peephole match functions */ static Pair* peephole_constant_op(zend_op* ops, int i, int num_ops) { return is_constant_op(ops + i) ? cons(i, 0) : 0; } static Pair* peephole_constant_expr(zend_op* ops, int i, int num_ops) { int j; /* next op after i */ int k; /* next op after j */ j = next_op(ops, i, num_ops); k = next_op(ops, j, num_ops); if (j == num_ops) { return 0; /* not enough ops left to match */ } /* Try to match a (LOAD_CONSTANT, LOAD_CONSTANT, pure-binary-op) tuple. */ if (ops[i].opcode == DARG_LOAD_CONSTANT && ops[j].opcode == DARG_LOAD_CONSTANT && k != num_ops && is_pure_binary_op(&ops[k])) { zend_op* const1_op = &ops[i]; zend_op* const2_op = &ops[j]; zend_op* binary_op = &ops[k]; if (binary_op->op1.op_type == IS_TMP_VAR && binary_op->op2.op_type == IS_TMP_VAR && const1_op->result.u.var == binary_op->op1.u.var && const2_op->result.u.var == binary_op->op2.u.var) { return cons(i, cons(j, cons(k, 0))); } } /* Try to match a (LOAD_CONSTANT, pure-binary-op) tuple. */ if (ops[i].opcode == DARG_LOAD_CONSTANT && is_pure_binary_op(&ops[j])) { zend_op* const1_op = &ops[i]; zend_op* binary_op = &ops[j]; if (binary_op->op1.op_type == IS_TMP_VAR && binary_op->op2.op_type == IS_CONST && const1_op->result.u.var == binary_op->op1.u.var) { return cons(i, cons(j, 0)); } } return 0; } static Pair* peephole_post_inc(zend_op* ops, int i, int num_ops) { int j; /* next op after i */ int k; /* next op after j */ j = next_op(ops, i, num_ops); k = next_op(ops, j, num_ops); if (j == num_ops || k == num_ops) { return 0; /* not enough ops left to match */ } /* Try to match a (FETCH_RW, POST_INC, FREE) tuple. */ if (ops[i].opcode == ZEND_FETCH_RW && ops[j].opcode == ZEND_POST_INC && ops[k].opcode == ZEND_FREE) { /* Insure that the fetch op reads into a register subsequently * incremented by the increment op, and that the free op subsequently * frees the temporary result used by the incr op. Basically, we're * just going to be SUPER careful that the rewrite is safe. */ zend_op* load_op = &ops[i]; zend_op* incr_op = &ops[j]; zend_op* free_op = &ops[k]; if (load_op->op2.u.fetch_type == ZEND_FETCH_LOCAL && load_op->op1.u.constant.type == IS_STRING && load_op->op1.op_type == IS_CONST && load_op->result.op_type != IS_CONST && incr_op->op1.op_type != IS_CONST && load_op->result.u.var == incr_op->op1.u.var && incr_op->result.op_type != IS_CONST && free_op->op1.op_type != IS_CONST && incr_op->result.u.var == free_op->op1.u.var) { return cons(i, cons(j, cons(k, 0))); } } return 0; } static Pair* peephole_inc(zend_op* ops, int i, int num_ops) { int j; /* next op after i */ int k; /* next op after j */ j = next_op(ops, i, num_ops); k = next_op(ops, j, num_ops); if (j == num_ops || k == num_ops) { return 0; /* not enough ops left to match */ } /* Try to match a (FETCH_RW, POST_INC, FREE) tuple. */ if (ops[i].opcode == ZEND_FETCH_RW && (ops[j].opcode == ZEND_POST_INC || ops[j].opcode == ZEND_POST_DEC ) && ops[k].opcode == ZEND_FREE) { /* Insure that the fetch op reads into a register subsequently * incremented by the increment op, and that the free op subsequently * frees the temporary result used by the incr op. Basically, we're * just going to be SUPER careful that the rewrite is safe. */ zend_op* load_op = &ops[i]; zend_op* incr_op = &ops[j]; zend_op* free_op = &ops[k]; if (load_op->op2.u.fetch_type == ZEND_FETCH_LOCAL && load_op->op1.u.constant.type == IS_STRING && load_op->op1.op_type == IS_CONST && load_op->result.op_type != IS_CONST && incr_op->op1.op_type != IS_CONST && load_op->result.u.var == incr_op->op1.u.var && incr_op->result.op_type != IS_CONST && free_op->op1.op_type != IS_CONST && incr_op->result.u.var == free_op->op1.u.var) { return cons(i, cons(j, cons(k, 0))); } } return 0; } static Pair* peephole_add_string(zend_op* ops, int i, int num_ops) { int j; /* next op after i */ Pair *p = NULL; int tmp_var_result; int tmp_var_op1; if (ops[i].opcode != ZEND_ADD_STRING || ops[i].result.op_type != IS_TMP_VAR || ops[i].op1.op_type != IS_TMP_VAR || ops[i].op2.op_type != IS_CONST) { return 0; } tmp_var_result = ops[i].result.u.var; tmp_var_op1 = ops[i].op1.u.var; for (j = next_op(ops, i, num_ops); j < num_ops; j = next_op(ops, j, num_ops)) { if (ops[j].opcode != ZEND_ADD_STRING) { return p; } if (ops[j].op2.op_type == IS_CONST && ops[j].result.op_type == IS_TMP_VAR && ops[j].op1.op_type == IS_TMP_VAR && ops[j].result.u.var == tmp_var_result && ops[j].op1.u.var == tmp_var_op1) { if (!p) { p = cons(j, cons(i, 0)); } else { p = cons(j, p); } } } return p; } /* }}} */ /* {{{ optimizer_rewrite_op_array */ zend_op_array* optimizer_rewrite_op_array(zend_op_array* op_array) { #define RESTART_PEEPHOLE_LOOP { pair_destroy(p); i = -1; continue; } Pair** jumps; int i; int jump_array_size; if (!op_array->opcodes) { return op_array; } jump_array_size = op_array->last; jumps = build_jump_array(op_array->opcodes, jump_array_size); for (i = 0; i < op_array->last; i++) { Pair* p; if (p = peephole_constant_op(op_array->opcodes, i, op_array->last)) { if (!are_branch_targets(cdr(p), jumps)) { rewrite_constant_op(op_array->opcodes, p); } RESTART_PEEPHOLE_LOOP; } if (p = peephole_constant_expr(op_array->opcodes, i, op_array->last)) { if (!are_branch_targets(cdr(p), jumps)) { rewrite_constant_expr(op_array->opcodes, p); } RESTART_PEEPHOLE_LOOP; } if (p = peephole_inc(op_array->opcodes, i, op_array->last)) { if (!are_branch_targets(cdr(p), jumps)) { rewrite_inc(op_array->opcodes, p); } RESTART_PEEPHOLE_LOOP; } if (p = peephole_add_string(op_array->opcodes, i, op_array->last)) { if (!are_branch_targets(cdr(p), jumps)) { rewrite_add_string(op_array->opcodes, p); } RESTART_PEEPHOLE_LOOP; } } op_array->last = compress_ops(op_array->opcodes, jumps, op_array->last); destroy_jump_array(jumps, jump_array_size); return op_array; #undef RESTART_PEEPHOLE_LOOP } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_compile.h +++ pear/PECL/optimizer/optimizer_compile.h /* $Id: optimizer_compile.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_COMPILE_H #define OPC_COMPILE_H #include "optimizer.h" extern zend_op_array* optimizer_rewrite_op_array(zend_op_array* op_array); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_debug.c +++ pear/PECL/optimizer/optimizer_debug.c /* $Id: optimizer_debug.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "optimizer_main.h" #include "optimizer.h" #include "optimizer_zend_util.h" #include <assert.h> /* {{{ horribly nasty string manip functions */ /* stores string rep of z in buf */ static void zval_to_string(char* buf, int size, zval* z) { zval copy; int use_copy; zend_make_printable_zval(z, &copy, &use_copy); if (use_copy) { z = &copy; } if (z->value.str.len == 0) { if (use_copy) { zval_dtor(z); } buf[0] = '\0'; return; } strncpy(buf, z->value.str.val, size-1); buf[size-1] = '\0'; } /* initializes buf if it hasn't been already */ static void init_buf(char** buf, int* size) { if (!*buf) { *size = 1; *buf = (char*) malloc(*size); assert(*buf); **buf = '\0'; } } /* expands buf */ static void expand_buf(char** buf, int* size, int cur_len, int add_len) { int min_size = cur_len + add_len + 1; if (min_size > *size) { char* new_buf; while (min_size > *size) { *size *= 2; } new_buf = (char*) malloc(*size); assert(new_buf); memcpy(new_buf, *buf, cur_len); new_buf[cur_len] = '\0'; free(*buf); *buf = new_buf; } } /* appends a char to buf */ static void append_char(char** buf, int* size, char ch) { int buf_len; buf_len = strlen(*buf); expand_buf(buf, size, buf_len, 1); (*buf)[buf_len] = ch; (*buf)[buf_len + 1] = '\0'; } /* appends an int to buf */ static void append_int(char** buf, int* size, int x) { char str[1024]; int buf_len, str_len; snprintf(str, sizeof(str)-1, "%d", x); str[sizeof(str)-1] = '\0'; buf_len = strlen(*buf); str_len = strlen(str); expand_buf(buf, size, buf_len, str_len); memcpy(*buf + buf_len, str, str_len + 1); } /* appends a string to buf */ static void append_str(char** buf, int* size, const char* str) { int buf_len, str_len; buf_len = strlen(*buf); str_len = strlen(str); expand_buf(buf, size, buf_len, str_len); memcpy(*buf + buf_len, str, str_len + 1); } /* append string repr. of a znode to buf */ static void append_znode(char** buf, int* size, znode* n) { switch (n->op_type) { case IS_CONST: { char str[1024]; zval_to_string(str, sizeof(str)-1, &n->u.constant); append_char(buf, size, '"'); append_str (buf, size, str); append_char(buf, size, '"'); break; } case IS_VAR: case IS_TMP_VAR: { append_char(buf, size, '$'); append_int (buf, size, n->u.var); break; } case IS_UNUSED: append_char(buf, size, '-'); default: assert(0); } } /* }}} */ /* {{{ show functions */ /* {{{ show_znode */ /* Converts a znode into a presentable zval. */ static zval* show_znode(znode* n) { zval* z = 0; ALLOC_INIT_ZVAL(z); array_init(z); add_assoc_string(z, "op_type", optimizer_zend_util_znode_op_type_to_string(n->op_type), 1); switch (n->op_type) { case IS_CONST: add_assoc_zval(z, "constant", duplicate_zval(&n->u.constant)); break; case IS_VAR: case IS_TMP_VAR: add_assoc_long(z, "temporary", n->u.var); break; default: add_assoc_string(z, "value", "???", 1); break; } return z; } /* }}} */ /* {{{ show_zend_op */ /* Converts a zend_op into a presentable zval. */ static zval* show_zend_op(int op_num, zend_op* op) { zval* z = 0; char* buf = 0; int size; init_buf(&buf, &size); ALLOC_INIT_ZVAL(z); array_init(z); add_assoc_string(z, "opcode", optimizer_zend_util_opcode_to_string(op->opcode), 1); add_assoc_long (z, "extended_value", op->extended_value); add_assoc_long (z, "lineno", op->lineno); add_assoc_long (z, "op_num", op_num); add_assoc_zval (z, "result", show_znode(&op->result)); add_assoc_zval (z, "op1", show_znode(&op->op1)); add_assoc_zval (z, "op2", show_znode(&op->op2)); // Generate "assembly" code for this zend_op. // TODO: fix this heinous code by parameterizing the display code.. I'm // thinking of string "codes" that describe how ops should be displayed // and associating them with the opcodes. E.g. ZEND_JMP might be "_O__" // indicating that the result is unused, op1 is an offset, and op2 and the // extended value are unused; ZEND_FETCH_R might be "ZZF_" indicating that // the result and op1 are znodes, op2 is a fetch type, and the extended // value is used. Much more concise that this crap. append_str (&buf, &size, optimizer_zend_util_opcode_to_string(op->opcode)); append_char (&buf, &size, ' '); switch (op->opcode) { case ZEND_JMP: append_int (&buf, &size, op->op1.u.opline_num); // jumps only break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMP_NO_CTOR: append_znode(&buf, &size, &op->op1); append_str (&buf, &size, ", "); append_int (&buf, &size, op->op2.u.opline_num); // jumps only break; case ZEND_JMPZNZ: append_znode(&buf, &size, &op->op1); append_str (&buf, &size, ", "); append_int (&buf, &size, op->op2.u.opline_num); // jumps only append_str (&buf, &size, ", "); append_int (&buf, &size, op->extended_value); // jumps only break; case ZEND_FETCH_R: case ZEND_FETCH_W: append_znode(&buf, &size, &op->result); append_str (&buf, &size, ", "); append_znode(&buf, &size, &op->op1); append_str (&buf, &size, ", "); append_str (&buf, &size, op->op2.u.fetch_type == ZEND_FETCH_LOCAL ? "LOCAL" : op->op2.u.fetch_type == ZEND_FETCH_GLOBAL ? "GLOBAL" : "STATIC"); break; default: append_znode(&buf, &size, &op->result); append_str (&buf, &size, ", "); append_znode(&buf, &size, &op->op1); append_str (&buf, &size, ", "); append_znode(&buf, &size, &op->op2); break; } add_assoc_string(z, "assembly", buf, 1); free(buf); return z; } /* }}} */ /* {{{ show_zend_op_array */ static zval* show_zend_op_array(zend_op_array* op_array) { zval* op_array_zval; ALLOC_INIT_ZVAL(op_array_zval); array_init(op_array_zval); add_assoc_long(op_array_zval, "type", op_array->type); if (op_array->arg_types) { zval* arg_types = 0; int num_arg_types = op_array->arg_types[0]; int i; array_init(arg_types); for (i = 1; i <= num_arg_types; i++) { add_next_index_long(arg_types, op_array->arg_types[i]); } add_assoc_zval(op_array_zval, "arg_types", arg_types); } else { add_assoc_string(op_array_zval, "arg_types", "null", 1); } if (op_array->function_name) { add_assoc_string(op_array_zval, "function_name", op_array->function_name, 1); } else { add_assoc_string(op_array_zval, "function_name", "null", 1); } if (op_array->refcount) { add_assoc_long(op_array_zval, "refcount", *(op_array->refcount)); } else { add_assoc_string(op_array_zval, "refcount", "null", 1); } if (op_array->opcodes) { zval* opcodes = 0; int i = 0; ALLOC_INIT_ZVAL(opcodes); array_init(opcodes); for (i = 0; i < op_array->last; i++) { zval* z = show_zend_op(i, &(op_array->opcodes[i])); add_next_index_zval(opcodes, z); } add_assoc_zval(op_array_zval, "opcodes", opcodes); } else { add_assoc_string(op_array_zval, "opcodes", "null", 1); } add_assoc_long(op_array_zval, "last", op_array->last); add_assoc_long(op_array_zval, "size", op_array->size); add_assoc_long(op_array_zval, "T", op_array->T); if (op_array->brk_cont_array) { add_assoc_string(op_array_zval, "brk_cont_array", "Coming Soon", 1); } else { add_assoc_string(op_array_zval, "brk_cont_array", "null", 1); } add_assoc_long(op_array_zval, "last_brk_cont", op_array->last_brk_cont); add_assoc_long(op_array_zval, "current_brk_cont", op_array->current_brk_cont); add_assoc_long(op_array_zval, "uses_globals", op_array->uses_globals); if (op_array->static_variables) { // FIXME //add_assoc_zval(op_array_zval, "static_variables", op_array->static_variables); } else { add_assoc_string(op_array_zval, "static_variables", "null", 1); } add_assoc_long(op_array_zval, "start_op", op_array->start_op - op_array->opcodes); add_assoc_long(op_array_zval, "backpatch_count", op_array->backpatch_count); add_assoc_bool(op_array_zval, "return_reference", op_array->return_reference); add_assoc_bool(op_array_zval, "done_pass_two", op_array->done_pass_two); if (op_array->filename) { add_assoc_string(op_array_zval, "filename", op_array->filename, 1); } else { add_assoc_string(op_array_zval, "filename", "null", 1); } return op_array_zval; } /* }}} */ /* }}} */ /* {{{ optimizer_debug_compile */ void optimizer_debug_compile(zval* retval, zval* filename) { zend_op_array* op_array; zval* new_functions; zval* new_classes; HashTable* function_table; HashTable* class_table; int i; /* Initialize return array. */ array_init(retval); /* * Before compiling the file, saves copies of the function and class * tables. We will later compare to these post-compilation to determine * which functions and classes exist in the compiled file. */ function_table = optimizer_zend_util_copy_function_table(CG(function_table)); class_table = optimizer_zend_util_copy_class_table(CG(class_table)); /* * Compile the file. */ convert_to_string_ex(&filename); op_array = compile_filename(ZEND_INCLUDE, filename TSRMLS_DC); /* * Now that we have compiled the file, compute the difference of the * current function and class tables with our saved copies. This is easy * because we can assume that things only get appended to the tables. */ /* Functions. */ ALLOC_INIT_ZVAL(new_functions); array_init(new_functions); // TODO -- this isn't working right now... it's disabled zend_hash_internal_pointer_reset(CG(function_table)); for (i = 0; i < zend_hash_num_elements(function_table); i++) { zend_hash_move_forward(CG(function_table)); /* skip first N elems */ } for (; i < zend_hash_num_elements(CG(function_table)); i++) { zend_function* fun = 0; zend_hash_get_current_data(CG(function_table), (void**) &fun); zend_hash_move_forward(CG(function_table)); // add_next_index_string(new_functions, fun->common.function_name, 1); add_assoc_zval(new_functions, fun->common.function_name, show_zend_op_array(&fun->op_array)); } zend_hash_internal_pointer_reset(CG(function_table)); add_assoc_zval(retval, "functions", new_functions); /* Classes. */ ALLOC_INIT_ZVAL(new_classes); array_init(new_classes); zend_hash_internal_pointer_reset(CG(class_table)); for (i = 0; i < zend_hash_num_elements(class_table); i++) { zend_hash_move_forward(CG(class_table)); /* skip first N elems */ } for (; i < zend_hash_num_elements(CG(class_table)); i++) { zend_class_entry* class = 0; zend_hash_get_current_data(CG(class_table), (void**) &class); add_next_index_string(new_classes, class->name, 1); zend_hash_move_forward(CG(class_table)); } zend_hash_internal_pointer_reset(CG(class_table)); add_assoc_zval(retval, "classes", new_classes); /* * Create a zval array and populate it with a presentable dump of the * contents of the compiled op_array, then store the zval array in retval * (with key = 'op_array'). */ add_assoc_zval(retval, "op_array", show_zend_op_array(op_array)); /* * Dump the contents of the function table, too. */ //free_op_array(op_array); // XXX: missing symbol? } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_debug.h +++ pear/PECL/optimizer/optimizer_debug.h /* $Id: optimizer_debug.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_DEBUG_H #define OPC_DEBUG_H #include "optimizer.h" extern void optimizer_debug_compile(zval* retval, zval* filename); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_instructions.c +++ pear/PECL/optimizer/optimizer_instructions.c /* $Id: optimizer_instructions.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "optimizer_main.h" #include "optimizer.h" #include "optimizer_zend_util.h" #include "optimizer_newopcodes.h" #include <assert.h> /* {{{ optimizer_handle_instructions */ void optimizer_handle_instructions(zend_execute_data *ptr) { zend_op* opline = ptr->opline; switch(opline->opcode) { case DARG_LOAD_CONSTANT: { ptr->Ts[opline->result.u.var].tmp_var = opline->op1.u.constant; zval_copy_ctor(&ptr->Ts[opline->result.u.var].tmp_var); break; } case DARG_INCDEC_VAR: { zval* varname = &opline->op1.u.constant; HashTable* target_symbol_table = EG(active_symbol_table); zval** retval; if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { zval *new_zval; ALLOC_ZVAL(new_zval); INIT_PZVAL(new_zval); *new_zval = EG(uninitialized_zval); zval_copy_ctor(new_zval); zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); new_zval->refcount++; zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); } switch(opline->op2.u.fetch_type) { case ZEND_POST_INC: /* ptr->Ts[opline->result.u.var].tmp_var = **retval; zendi_zval_copy_ctor(ptr->Ts[opline->result.u.var].tmp_var); */ increment_function(*retval); break; case ZEND_POST_DEC: /* ptr->Ts[opline->result.u.var].tmp_var = **retval; zendi_zval_copy_ctor(ptr->Ts[opline->result.u.var].tmp_var); */ decrement_function(*retval); break; } break; } } } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_instructions.h +++ pear/PECL/optimizer/optimizer_instructions.h /* $Id: optimizer_instructions.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_COMPILE_H #define OPC_COMPILE_H #include "optimizer.h" extern void optimizer_handle_instructions(zend_execute_data *ptr); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_main.c +++ pear/PECL/optimizer/optimizer_main.c /* $Id: optimizer_main.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "optimizer_main.h" #include "optimizer.h" #include "optimizer_compile.h" /* Pointer to the original Zend engine compile_file function. */ static ZEND_API zend_op_array* (*old_compile_file) (zend_file_handle*, int TSRMLS_DC); /* Pointer to the original Zend engine execute function. */ static ZEND_API void (*old_execute)(zend_op_array* TSRMLS_DC); /* Overrides zend_compile_file */ static ZEND_API zend_op_array* optimizer_compile_file(zend_file_handle* h, int type TSRMLS_DC) { return optimizer_rewrite_op_array(old_compile_file(h, type)); } /* Overides zend_execute */ static ZEND_API void optimizer_execute(zend_op_array* op_array TSRMLS_DC) { old_execute(op_array); } static ZEND_API void optimizer_secret_opcodes(zend_execute_data* data TSRMLS_DC) { optimizer_handle_instructions(data); } /* {{{ OPC module init and shutdown */ int optimizer_main_module_init() { old_compile_file = zend_compile_file; zend_compile_file = optimizer_compile_file; zend_secret_opcodes = optimizer_secret_opcodes; return 0; } int optimizer_main_module_shutdown() { zend_compile_file = old_compile_file; return 0; } /* }}} */ /* {{{ OPC request init and shutdown */ int optimizer_main_request_init() { return 0; } int optimizer_main_request_shutdown() { return 0; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_main.h +++ pear/PECL/optimizer/optimizer_main.h /* $Id: optimizer_main.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_MAIN_H #define OPC_MAIN_H extern int optimizer_main_module_init(); extern int optimizer_main_module_shutdown(); extern int optimizer_main_request_init(); extern int optimizer_main_request_shutdown(); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_newopcodes.h +++ pear/PECL/optimizer/optimizer_newopcodes.h /* $Id: optimizer_newopcodes.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_NEWOPCODES_H #define OPC_NEWOPCODES_H #define DARG_LOAD_CONSTANT 107 #define DARG_INCDEC_VAR 108 #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_pair.c +++ pear/PECL/optimizer/optimizer_pair.c /* $Id: optimizer_pair.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "optimizer_pair.h" #include <assert.h> struct Pair { int v; Pair* n; }; Pair* cons(int x, Pair* p) { Pair* q = (Pair*) malloc(sizeof(Pair)); q->v = x; q->n = p; return q; } int car(Pair* p) { assert(p); return p->v; } Pair* cdr(Pair* p) { assert(p); return p->n; } void pair_set_car(Pair* p, int v) { assert(p); p->v = v; } int pair_length(Pair* p) { return p ? 1 + pair_length(cdr(p)) : 0; } void pair_destroy(Pair* p) { while (p) { Pair* q = p; p = cdr(p); free(q); } } Pair* pair_copy(Pair* p) { return p ? cons(car(p), pair_copy(cdr(p))) : 0; } Pair* pair_filter(int (*pred)(int), Pair* p) { return p ? pred(car(p)) ? pair_filter(pred, cdr(p)) : cons(car(p), pair_filter(pred, cdr(p))) : 0; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_pair.h +++ pear/PECL/optimizer/optimizer_pair.h /* $Id: optimizer_pair.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_PAIR_H #define OPC_PAIR_H typedef struct Pair Pair; /* prepends x to p */ extern Pair* cons(int x, Pair* p); /* returns the list head */ extern int car(Pair* p); /* returns the list tail */ extern Pair* cdr(Pair* p); /* changes value of list head */ extern void pair_set_car(Pair* p, int v); /* returns the length of the list */ extern int pair_length(Pair* p); /* deallocates a list */ extern void pair_destroy(Pair* p); /* returns a copy of the given list */ extern Pair* pair_copy(Pair* p); /* filters elements from p where predicate is true (returns a list copy) */ extern Pair* pair_filter(int (*pred)(int), Pair* p); #define make_pair(x, y) cons(x, cons(y, 0)) #define cadr(p) car(cdr(p)) #define cddr(p) cdr(cdr(p)) #define caddr(p) car(cdr(cdr(p))) #define cdddr(p) cdr(cdr(cdr(p))) #define cadddr(p) car(cdr(cdr(cdr(p)))) #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_zend_util.c +++ pear/PECL/optimizer/optimizer_zend_util.c #include "optimizer_zend_util.h" zval* duplicate_zval(zval* v) { zval* copy; ALLOC_INIT_ZVAL(copy); *copy = *v; zval_copy_ctor(copy); return copy; } HashTable* optimizer_zend_util_copy_function_table(HashTable* t) { HashTable* p; zend_function tmp_func; p = (HashTable*) emalloc(sizeof(HashTable)); zend_hash_init_ex(p, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_hash_copy(p, t, NULL, &tmp_func, sizeof(zend_function)); return p; } HashTable* optimizer_zend_util_copy_class_table(HashTable* t) { HashTable* p; zend_class_entry tmp_class; p = (HashTable*) emalloc(sizeof(HashTable)); zend_hash_init_ex(p, 10, NULL, ZEND_CLASS_DTOR, 1, 0); zend_hash_copy(p, t, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry)); return p; } const char* optimizer_zend_util_znode_op_type_to_string(int op_type) { static const char S_IS_CONST[] = "IS_CONST"; static const char S_IS_TMP_VAR[] = "IS_TMP_VAR"; static const char S_IS_VAR[] = "IS_VAR"; static const char S_IS_UNUSED[] = "IS_UNUSED"; switch (op_type) { case IS_CONST: return S_IS_CONST; case IS_TMP_VAR: return S_IS_TMP_VAR; case IS_VAR: return S_IS_VAR; case IS_UNUSED: return S_IS_UNUSED; default: assert(0); } } const char* optimizer_zend_util_opcode_to_string(int opcode) { static const char S_ZEND_NOP[] = "NOP"; static const char S_ZEND_ADD[] = "ADD"; static const char S_ZEND_SUB[] = "SUB"; static const char S_ZEND_MUL[] = "MUL"; static const char S_ZEND_DIV[] = "DIV"; static const char S_ZEND_MOD[] = "MOD"; static const char S_ZEND_SL[] = "SL"; static const char S_ZEND_SR[] = "SR"; static const char S_ZEND_CONCAT[] = "CONCAT"; static const char S_ZEND_BW_OR[] = "BW_OR"; static const char S_ZEND_BW_AND[] = "BW_AND"; static const char S_ZEND_BW_XOR[] = "BW_XOR"; static const char S_ZEND_BW_NOT[] = "BW_NOT"; static const char S_ZEND_BOOL_NOT[] = "BOOL_NOT"; static const char S_ZEND_BOOL_XOR[] = "BOOL_XOR"; static const char S_ZEND_IS_IDENTICAL[] = "IS_IDENTICAL"; static const char S_ZEND_IS_NOT_IDENTICAL[] = "IS_NOT_IDENTICAL"; static const char S_ZEND_IS_EQUAL[] = "IS_EQUAL"; static const char S_ZEND_IS_NOT_EQUAL[] = "IS_NOT_EQUAL"; static const char S_ZEND_IS_SMALLER[] = "IS_SMALLER"; static const char S_ZEND_IS_SMALLER_OR_EQUAL[] = "IS_SMALLER_OR_EQUAL"; static const char S_ZEND_CAST[] = "CAST"; static const char S_ZEND_QM_ASSIGN[] = "QM_ASSIGN"; static const char S_ZEND_ASSIGN_ADD[] = "ASSIGN_ADD"; static const char S_ZEND_ASSIGN_SUB[] = "ASSIGN_SUB"; static const char S_ZEND_ASSIGN_MUL[] = "ASSIGN_MUL"; static const char S_ZEND_ASSIGN_DIV[] = "ASSIGN_DIV"; static const char S_ZEND_ASSIGN_MOD[] = "ASSIGN_MOD"; static const char S_ZEND_ASSIGN_SL[] = "ASSIGN_SL"; static const char S_ZEND_ASSIGN_SR[] = "ASSIGN_SR"; static const char S_ZEND_ASSIGN_CONCAT[] = "ASSIGN_CONCAT"; static const char S_ZEND_ASSIGN_BW_OR[] = "ASSIGN_BW_OR"; static const char S_ZEND_ASSIGN_BW_AND[] = "ASSIGN_BW_AND"; static const char S_ZEND_ASSIGN_BW_XOR[] = "ASSIGN_BW_XOR"; static const char S_ZEND_PRE_INC[] = "PRE_INC"; static const char S_ZEND_PRE_DEC[] = "PRE_DEC"; static const char S_ZEND_POST_INC[] = "POST_INC"; static const char S_ZEND_POST_DEC[] = "POST_DEC"; static const char S_ZEND_ASSIGN[] = "ASSIGN"; static const char S_ZEND_ASSIGN_REF[] = "ASSIGN_REF"; static const char S_ZEND_ECHO[] = "ECHO"; static const char S_ZEND_PRINT[] = "PRINT"; static const char S_ZEND_JMP[] = "JMP"; static const char S_ZEND_JMPZ[] = "JMPZ"; static const char S_ZEND_JMPNZ[] = "JMPNZ"; static const char S_ZEND_JMPZNZ[] = "JMPZNZ"; static const char S_ZEND_JMPZ_EX[] = "JMPZ_EX"; static const char S_ZEND_JMPNZ_EX[] = "JMPNZ_EX"; static const char S_ZEND_CASE[] = "CASE"; static const char S_ZEND_SWITCH_FREE[] = "SWITCH_FREE"; static const char S_ZEND_BRK[] = "BRK"; static const char S_ZEND_CONT[] = "CONT"; static const char S_ZEND_BOOL[] = "BOOL"; static const char S_ZEND_INIT_STRING[] = "INIT_STRING"; static const char S_ZEND_ADD_CHAR[] = "ADD_CHAR"; static const char S_ZEND_ADD_STRING[] = "ADD_STRING"; static const char S_ZEND_ADD_VAR[] = "ADD_VAR"; static const char S_ZEND_BEGIN_SILENCE[] = "BEGIN_SILENCE"; static const char S_ZEND_END_SILENCE[] = "END_SILENCE"; static const char S_ZEND_INIT_FCALL_BY_NAME[] = "INIT_FCALL_BY_NAME"; static const char S_ZEND_DO_FCALL[] = "DO_FCALL"; static const char S_ZEND_DO_FCALL_BY_NAME[] = "DO_FCALL_BY_NAME"; static const char S_ZEND_RETURN[] = "RETURN"; static const char S_ZEND_RECV[] = "RECV"; static const char S_ZEND_RECV_INIT[] = "RECV_INIT"; static const char S_ZEND_SEND_VAL[] = "SEND_VAL"; static const char S_ZEND_SEND_VAR[] = "SEND_VAR"; static const char S_ZEND_SEND_REF[] = "SEND_REF"; static const char S_ZEND_NEW[] = "NEW"; static const char S_ZEND_JMP_NO_CTOR[] = "JMP_NO_CTOR"; static const char S_ZEND_FREE[] = "FREE"; static const char S_ZEND_INIT_ARRAY[] = "INIT_ARRAY"; static const char S_ZEND_ADD_ARRAY_ELEMENT[] = "ADD_ARRAY_ELEMENT"; static const char S_ZEND_INCLUDE_OR_EVAL[] = "INCLUDE_OR_EVAL"; static const char S_ZEND_UNSET_VAR[] = "UNSET_VAR"; static const char S_ZEND_UNSET_DIM_OBJ[] = "UNSET_DIM_OBJ"; static const char S_ZEND_ISSET_ISEMPTY[] = "ISSET_ISEMPTY"; static const char S_ZEND_FE_RESET[] = "FE_RESET"; static const char S_ZEND_FE_FETCH[] = "FE_FETCH"; static const char S_ZEND_EXIT[] = "EXIT"; static const char S_ZEND_FETCH_R[] = "FETCH_R"; static const char S_ZEND_FETCH_DIM_R[] = "FETCH_DIM_R"; static const char S_ZEND_FETCH_OBJ_R[] = "FETCH_OBJ_R"; static const char S_ZEND_FETCH_W[] = "FETCH_W"; static const char S_ZEND_FETCH_DIM_W[] = "FETCH_DIM_W"; static const char S_ZEND_FETCH_OBJ_W[] = "FETCH_OBJ_W"; static const char S_ZEND_FETCH_RW[] = "FETCH_RW"; static const char S_ZEND_FETCH_DIM_RW[] = "FETCH_DIM_RW"; static const char S_ZEND_FETCH_OBJ_RW[] = "FETCH_OBJ_RW"; static const char S_ZEND_FETCH_IS[] = "FETCH_IS"; static const char S_ZEND_FETCH_DIM_IS[] = "FETCH_DIM_IS"; static const char S_ZEND_FETCH_OBJ_IS[] = "FETCH_OBJ_IS"; static const char S_ZEND_FETCH_FUNC_ARG[] = "FETCH_FUNC_ARG"; static const char S_ZEND_FETCH_DIM_FUNC_ARG[] = "FETCH_DIM_FUNC_ARG"; static const char S_ZEND_FETCH_OBJ_FUNC_ARG[] = "FETCH_OBJ_FUNC_ARG"; static const char S_ZEND_FETCH_UNSET[] = "FETCH_UNSET"; static const char S_ZEND_FETCH_DIM_UNSET[] = "FETCH_DIM_UNSET"; static const char S_ZEND_FETCH_OBJ_UNSET[] = "FETCH_OBJ_UNSET"; static const char S_ZEND_FETCH_DIM_TMP_VAR[] = "FETCH_DIM_TMP_VAR"; static const char S_ZEND_FETCH_CONSTANT[] = "FETCH_CONSTANT"; static const char S_ZEND_DECLARE_FUNCTION_OR_CLASS[] = "DECLARE_FUNCTION_OR_CLASS"; static const char S_ZEND_EXT_STMT[] = "EXT_STMT"; static const char S_ZEND_EXT_FCALL_BEGIN[] = "EXT_FCALL_BEGIN"; static const char S_ZEND_EXT_FCALL_END[] = "EXT_FCALL_END"; static const char S_ZEND_EXT_NOP[] = "EXT_NOP"; static const char S_ZEND_TICKS[] = "TICKS"; static const char S_ZEND_SEND_VAR_NO_REF[] = "SEND_VAR_NO_REF"; // extended opcodes static const char S_DARG_LOAD_CONSTANT[] = "DARG_LOAD_CONSTANT"; static const char S_DARG_INCDEC_VAR[] = "DARG_INCDEC_VAR"; switch (opcode) { case ZEND_NOP: return S_ZEND_NOP; case ZEND_ADD: return S_ZEND_ADD; case ZEND_SUB: return S_ZEND_SUB; case ZEND_MUL: return S_ZEND_MUL; case ZEND_DIV: return S_ZEND_DIV; case ZEND_MOD: return S_ZEND_MOD; case ZEND_SL: return S_ZEND_SL; case ZEND_SR: return S_ZEND_SR; case ZEND_CONCAT: return S_ZEND_CONCAT; case ZEND_BW_OR: return S_ZEND_BW_OR; case ZEND_BW_AND: return S_ZEND_BW_AND; case ZEND_BW_XOR: return S_ZEND_BW_XOR; case ZEND_BW_NOT: return S_ZEND_BW_NOT; case ZEND_BOOL_NOT: return S_ZEND_BOOL_NOT; case ZEND_BOOL_XOR: return S_ZEND_BOOL_XOR; case ZEND_IS_IDENTICAL: return S_ZEND_IS_IDENTICAL; case ZEND_IS_NOT_IDENTICAL: return S_ZEND_IS_NOT_IDENTICAL; case ZEND_IS_EQUAL: return S_ZEND_IS_EQUAL; case ZEND_IS_NOT_EQUAL: return S_ZEND_IS_NOT_EQUAL; case ZEND_IS_SMALLER: return S_ZEND_IS_SMALLER; case ZEND_IS_SMALLER_OR_EQUAL: return S_ZEND_IS_SMALLER_OR_EQUAL; case ZEND_CAST: return S_ZEND_CAST; case ZEND_QM_ASSIGN: return S_ZEND_QM_ASSIGN; case ZEND_ASSIGN_ADD: return S_ZEND_ASSIGN_ADD; case ZEND_ASSIGN_SUB: return S_ZEND_ASSIGN_SUB; case ZEND_ASSIGN_MUL: return S_ZEND_ASSIGN_MUL; case ZEND_ASSIGN_DIV: return S_ZEND_ASSIGN_DIV; case ZEND_ASSIGN_MOD: return S_ZEND_ASSIGN_MOD; case ZEND_ASSIGN_SL: return S_ZEND_ASSIGN_SL; case ZEND_ASSIGN_SR: return S_ZEND_ASSIGN_SR; case ZEND_ASSIGN_CONCAT: return S_ZEND_ASSIGN_CONCAT; case ZEND_ASSIGN_BW_OR: return S_ZEND_ASSIGN_BW_OR; case ZEND_ASSIGN_BW_AND: return S_ZEND_ASSIGN_BW_AND; case ZEND_ASSIGN_BW_XOR: return S_ZEND_ASSIGN_BW_XOR; case ZEND_PRE_INC: return S_ZEND_PRE_INC; case ZEND_PRE_DEC: return S_ZEND_PRE_DEC; case ZEND_POST_INC: return S_ZEND_POST_INC; case ZEND_POST_DEC: return S_ZEND_POST_DEC; case ZEND_ASSIGN: return S_ZEND_ASSIGN; case ZEND_ASSIGN_REF: return S_ZEND_ASSIGN_REF; case ZEND_ECHO: return S_ZEND_ECHO; case ZEND_PRINT: return S_ZEND_PRINT; case ZEND_JMP: return S_ZEND_JMP; case ZEND_JMPZ: return S_ZEND_JMPZ; case ZEND_JMPNZ: return S_ZEND_JMPNZ; case ZEND_JMPZNZ: return S_ZEND_JMPZNZ; case ZEND_JMPZ_EX: return S_ZEND_JMPZ_EX; case ZEND_JMPNZ_EX: return S_ZEND_JMPNZ_EX; case ZEND_CASE: return S_ZEND_CASE; case ZEND_SWITCH_FREE: return S_ZEND_SWITCH_FREE; case ZEND_BRK: return S_ZEND_BRK; case ZEND_CONT: return S_ZEND_CONT; case ZEND_BOOL: return S_ZEND_BOOL; case ZEND_INIT_STRING: return S_ZEND_INIT_STRING; case ZEND_ADD_CHAR: return S_ZEND_ADD_CHAR; case ZEND_ADD_STRING: return S_ZEND_ADD_STRING; case ZEND_ADD_VAR: return S_ZEND_ADD_VAR; case ZEND_BEGIN_SILENCE: return S_ZEND_BEGIN_SILENCE; case ZEND_END_SILENCE: return S_ZEND_END_SILENCE; case ZEND_INIT_FCALL_BY_NAME: return S_ZEND_INIT_FCALL_BY_NAME; case ZEND_DO_FCALL: return S_ZEND_DO_FCALL; case ZEND_DO_FCALL_BY_NAME: return S_ZEND_DO_FCALL_BY_NAME; case ZEND_RETURN: return S_ZEND_RETURN; case ZEND_RECV: return S_ZEND_RECV; case ZEND_RECV_INIT: return S_ZEND_RECV_INIT; case ZEND_SEND_VAL: return S_ZEND_SEND_VAL; case ZEND_SEND_VAR: return S_ZEND_SEND_VAR; case ZEND_SEND_REF: return S_ZEND_SEND_REF; case ZEND_NEW: return S_ZEND_NEW; case ZEND_JMP_NO_CTOR: return S_ZEND_JMP_NO_CTOR; case ZEND_FREE: return S_ZEND_FREE; case ZEND_INIT_ARRAY: return S_ZEND_INIT_ARRAY; case ZEND_ADD_ARRAY_ELEMENT: return S_ZEND_ADD_ARRAY_ELEMENT; case ZEND_INCLUDE_OR_EVAL: return S_ZEND_INCLUDE_OR_EVAL; case ZEND_UNSET_VAR: return S_ZEND_UNSET_VAR; case ZEND_UNSET_DIM_OBJ: return S_ZEND_UNSET_DIM_OBJ; case ZEND_ISSET_ISEMPTY: return S_ZEND_ISSET_ISEMPTY; case ZEND_FE_RESET: return S_ZEND_FE_RESET; case ZEND_FE_FETCH: return S_ZEND_FE_FETCH; case ZEND_EXIT: return S_ZEND_EXIT; case ZEND_FETCH_R: return S_ZEND_FETCH_R; case ZEND_FETCH_DIM_R: return S_ZEND_FETCH_DIM_R; case ZEND_FETCH_OBJ_R: return S_ZEND_FETCH_OBJ_R; case ZEND_FETCH_W: return S_ZEND_FETCH_W; case ZEND_FETCH_DIM_W: return S_ZEND_FETCH_DIM_W; case ZEND_FETCH_OBJ_W: return S_ZEND_FETCH_OBJ_W; case ZEND_FETCH_RW: return S_ZEND_FETCH_RW; case ZEND_FETCH_DIM_RW: return S_ZEND_FETCH_DIM_RW; case ZEND_FETCH_OBJ_RW: return S_ZEND_FETCH_OBJ_RW; case ZEND_FETCH_IS: return S_ZEND_FETCH_IS; case ZEND_FETCH_DIM_IS: return S_ZEND_FETCH_DIM_IS; case ZEND_FETCH_OBJ_IS: return S_ZEND_FETCH_OBJ_IS; case ZEND_FETCH_FUNC_ARG: return S_ZEND_FETCH_FUNC_ARG; case ZEND_FETCH_DIM_FUNC_ARG: return S_ZEND_FETCH_DIM_FUNC_ARG; case ZEND_FETCH_OBJ_FUNC_ARG: return S_ZEND_FETCH_OBJ_FUNC_ARG; case ZEND_FETCH_UNSET: return S_ZEND_FETCH_UNSET; case ZEND_FETCH_DIM_UNSET: return S_ZEND_FETCH_DIM_UNSET; case ZEND_FETCH_OBJ_UNSET: return S_ZEND_FETCH_OBJ_UNSET; case ZEND_FETCH_DIM_TMP_VAR: return S_ZEND_FETCH_DIM_TMP_VAR; case ZEND_FETCH_CONSTANT: return S_ZEND_FETCH_CONSTANT; case ZEND_DECLARE_FUNCTION_OR_CLASS: return S_ZEND_DECLARE_FUNCTION_OR_CLASS; case ZEND_EXT_STMT: return S_ZEND_EXT_STMT; case ZEND_EXT_FCALL_BEGIN: return S_ZEND_EXT_FCALL_BEGIN; case ZEND_EXT_FCALL_END: return S_ZEND_EXT_FCALL_END; case ZEND_EXT_NOP: return S_ZEND_EXT_NOP; case ZEND_TICKS: return S_ZEND_TICKS; case ZEND_SEND_VAR_NO_REF: return S_ZEND_SEND_VAR_NO_REF; // Consider these opcodes armed and dangerous. Not approved by Zend!! case DARG_LOAD_CONSTANT: return S_DARG_LOAD_CONSTANT; case DARG_INCDEC_VAR: return S_DARG_INCDEC_VAR; default: assert(0); } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/optimizer_zend_util.h +++ pear/PECL/optimizer/optimizer_zend_util.h /* $Id: optimizer_zend_util.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef OPC_ZEND_UTIL_H #define OPC_ZEND_UTIL_H #include "optimizer.h" #include "optimizer_newopcodes.h" extern zval* duplicate_zval(zval* v); extern HashTable* optimizer_zend_util_copy_function_table(HashTable* t); extern HashTable* optimizer_zend_util_copy_class_table(HashTable* t); extern const char* optimizer_zend_util_znode_op_type_to_string(int op_type); extern const char* optimizer_zend_util_opcode_to_string(int opcode); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/php_optimizer.c +++ pear/PECL/optimizer/php_optimizer.c /* $Id: php_optimizer.c,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #include "php_optimizer.h" #include "optimizer_debug.h" #include "optimizer_main.h" #include "php_globals.h" #include "zend_extensions.h" #include "ext/standard/info.h" /* {{{ ZEND_DECLARE_MODULE_GLOBALS(optimizer) */ ZEND_DECLARE_MODULE_GLOBALS(optimizer) static void php_optimizer_init_globals(zend_optimizer_globals* optimizer_globals TSRMLS_DC) { optimizer_globals->global1 = 0; optimizer_globals->global2 = 0; } #ifdef ZTS static void php_optimizer_shutdown_globals(zend_optimizer_globals* optimizer_globals TSRMLS_DC) { optimizer_globals->global1 = 0; optimizer_globals->global2 = 0; } #endif /* }}} */ /* {{{ PHP_MINFO_FUNCTION(optimizer) */ static PHP_MINFO_FUNCTION(optimizer) { php_info_print_table_start(); php_info_print_table_row(2, "What does OPC stand for?", "enabled" ); php_info_print_table_end(); } /* }}} */ /* {{{ PHP_MINIT_FUNCTION(optimizer) */ static PHP_MINIT_FUNCTION(optimizer) { ZEND_INIT_MODULE_GLOBALS(optimizer, php_optimizer_init_globals, php_optimizer_shutdown_globals); REGISTER_LONG_CONSTANT("OPC_SOME_CONSTANT", 1, CONST_CS | CONST_PERSISTENT); optimizer_main_module_init(); return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION(optimizer) */ static PHP_MSHUTDOWN_FUNCTION(optimizer) { optimizer_main_module_shutdown(); return SUCCESS; } /* }}} */ /* {{{ PHP_RINIT_FUNCTION(optimizer) */ static PHP_RINIT_FUNCTION(optimizer) { optimizer_main_request_init(); return SUCCESS; } /* }}} */ /* {{{ PHP_RSHUTDOWN_FUNCTION(optimizer) */ static PHP_RSHUTDOWN_FUNCTION(optimizer) { optimizer_main_request_shutdown(); return SUCCESS; } /* }}} */ /* {{{ proto int optimizer_debug_compile(filename) Returns true */ PHP_FUNCTION(optimizer_debug_compile) { zval** filename; /* first parameter */ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &filename) == FAILURE) { WRONG_PARAM_COUNT; } optimizer_debug_compile(return_value, *filename); } /* }}} */ /* {{{ module definition structures */ function_entry optimizer_functions[] = { PHP_FE(optimizer_debug_compile, NULL) {NULL, NULL, NULL} }; zend_module_entry optimizer_module_entry = { STANDARD_MODULE_HEADER, "optimizer", optimizer_functions, PHP_MINIT(optimizer), PHP_MSHUTDOWN(optimizer), PHP_RINIT(optimizer), NULL, PHP_MINFO(optimizer), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_OPC ZEND_GET_MODULE(optimizer) #endif /* }}} */ /* {{{ zend extension definitions */ ZEND_DLEXPORT int optimizer_zend_startup(zend_extension* e) { return zend_startup_module(&optimizer_module_entry); } ZEND_DLEXPORT void optimizer_zend_shutdown(zend_extension* e) { /* Do nothing */ } #ifndef ZEND_EXT_API #define ZEND_EXT_API ZEND_DLEXPORT #endif ZEND_EXTENSION(); ZEND_DLEXPORT zend_extension zend_extension_entry = { "OPC", "[version]", "[authors]", "[url]", "[copyright]", optimizer_zend_startup, optimizer_zend_shutdown, NULL, /* activate_func_t */ NULL, /* deactivate_func_t */ NULL, /* message_handler_func_t */ NULL, /* op_array_handler_func_t */ NULL, /* statement_handler_func_t */ NULL, /* fcall_begin_handler_func_t */ NULL, /* fcall_end_handler_func_t */ NULL, /* op_array_ctor_func_t */ NULL, /* op_array_dtor_func_t */ STANDARD_ZEND_EXTENSION_PROPERTIES }; /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/php_optimizer.h +++ pear/PECL/optimizer/php_optimizer.h /* $Id: php_optimizer.h,v 1.1 2002/11/04 23:46:20 gschlossnagle Exp $ */ #ifndef PHP_OPC_H #define PHP_OPC_H #include "php.h" PHP_FUNCTION(optimizer_debug_compile); extern zend_module_entry optimizer_module_entry; #define optimizer_module_ptr &optimizer_module_entry ZEND_BEGIN_MODULE_GLOBALS(optimizer) int global1; int global2; ZEND_END_MODULE_GLOBALS(optimizer) #ifdef ZTS # define OPC_G(v) TSRMG(optimizer_globals_id, zend_optimizer_globals *, v) #else # define OPC_G(v) (optimizer_globals.v) #endif #define phpext_optimizer_ptr optimizer_module_ptr #endif /* PHP_OPC_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */ Index: pear/PECL/optimizer/zend.patch +++ pear/PECL/optimizer/zend.patch Index: Zend/zend.c =================================================================== RCS file: /repository/Zend/zend.c,v retrieving revision 1.161 diff -u -3 -r1.161 zend.c --- Zend/zend.c 12 Oct 2002 20:35:34 -0000 1.161 +++ Zend/zend.c 30 Oct 2002 20:50:54 -0000 @@ -424,6 +424,7 @@ zend_on_timeout = utility_functions->on_timeout; zend_compile_file = compile_file; + zend_secret_opcodes = NULL; zend_execute = execute; zend_execute_internal = NULL; /* saves one function call if the zend_execute_internal is not used */ Index: Zend/zend_execute.c =================================================================== RCS file: /repository/Zend/zend_execute.c,v retrieving revision 1.314 diff -u -3 -r1.314 zend_execute.c --- Zend/zend_execute.c 18 Oct 2002 10:16:51 -0000 1.314 +++ Zend/zend_execute.c 30 Oct 2002 20:50:55 -0000 @@ -994,9 +994,11 @@ EX(opline)++; \ continue; + ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) { zend_execute_data execute_data; + int i; /* Initialize execute_data */ EX(fbc) = NULL; @@ -1039,7 +1041,6 @@ FREE_ZVAL(globals); } } - while (1) { #ifdef ZEND_WIN32 if (EG(timed_out)) { @@ -2467,7 +2468,12 @@ case ZEND_EXT_NOP: case ZEND_NOP: NEXT_OPCODE(); - EMPTY_SWITCH_DEFAULT_CASE() + default: + if(zend_secret_opcodes) { + zend_secret_opcodes(&execute_data); + } + NEXT_OPCODE(); + } } Index: Zend/zend_execute.h =================================================================== RCS file: /repository/Zend/zend_execute.h,v retrieving revision 1.47 diff -u -3 -r1.47 zend_execute.h --- Zend/zend_execute.h 1 Oct 2002 17:20:12 -0000 1.47 +++ Zend/zend_execute.h 30 Oct 2002 20:50:55 -0000 @@ -28,6 +28,7 @@ #include "zend_execute_globals.h" BEGIN_EXTERN_C() +ZEND_API extern void (*zend_secret_opcodes)(zend_execute_data *execute_data_ptr TSRMLS_DC); ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC); ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC); Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/Zend/zend_execute_API.c,v retrieving revision 1.155 diff -u -3 -r1.155 zend_execute_API.c --- Zend/zend_execute_API.c 10 Oct 2002 16:27:52 -0000 1.155 +++ Zend/zend_execute_API.c 30 Oct 2002 20:50:55 -0000 @@ -34,6 +34,7 @@ #endif +ZEND_API void (*zend_secret_opcodes)(zend_execute_data *execute_data_ptr TSRMLS_DC); ZEND_API void (*zend_execute)(zend_op_array *op_array TSRMLS_DC); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC);
« previous php.pear.cvs (#7287) next »