source: trunk/mod_optimizer/xc_optimizer.c

Last change on this file was 1561, checked in by moo, 2 weeks ago

fix build for older PHP

  • Property svn:eol-style set to native
File size: 16.6 KB
Line 
1#include "xc_optimizer.h"
2#include "xcache/xc_extension.h"
3#include "xcache/xc_ini.h"
4#include "xcache/xc_utils.h"
5#include "util/xc_vector.h"
6#include "util/xc_trace.h"
7#include "xcache_globals.h"
8
9#include "ext/standard/info.h"
10
11#ifdef XCACHE_DEBUG
12#   include "xc_processor.h"
13#   include "xcache/xc_const_string.h"
14#   include "xcache/xc_opcode_spec.h"
15#   include "ext/standard/php_var.h"
16#endif
17
18#ifdef IS_CV
19#   define XCACHE_IS_CV IS_CV
20#else
21#   define XCACHE_IS_CV 16
22#endif
23
24#ifdef ZEND_ENGINE_2_4
25#   undef Z_OP_CONSTANT
26/* Z_OP_CONSTANT is used before pass_two is applied */
27#   define Z_OP_CONSTANT(op) op_array->literals[(op).constant].constant
28#endif
29
30typedef zend_uint bbid_t;
31#define BBID_INVALID ((bbid_t) -1)
32/* {{{ basic block */
33typedef struct _bb_t {
34    bbid_t     id;
35    zend_bool  used;
36
37    zend_bool  alloc;
38    zend_op   *opcodes;
39    int        count;
40    int        size;
41
42    bbid_t     fall;
43
44    zend_uint  opnum; /* opnum after joining basic block */
45} bb_t;
46/* }}} */
47
48/* basic blocks */
49typedef xc_vector_t bbs_t;
50
51/* op array helper functions */
52static int op_array_convert_switch(zend_op_array *op_array) /* {{{ */
53{
54    zend_uint i;
55
56    if (op_array->brk_cont_array == NULL) {
57        return SUCCESS;
58    }
59
60    for (i = 0; i < op_array->last; i ++) {
61        zend_op *opline = &op_array->opcodes[i];
62        zend_brk_cont_element *jmp_to;
63        zend_bool can_convert = 1;
64        int array_offset, nest_levels;
65
66        switch (opline->opcode) {
67        case ZEND_BRK:
68        case ZEND_CONT:
69            break;
70
71#ifdef ZEND_GOTO
72        case ZEND_GOTO:
73#endif
74            continue;
75
76        default:
77            continue;
78        }
79
80        if (Z_OP_TYPE(opline->op2) != IS_CONST
81         || Z_OP_CONSTANT(opline->op2).type != IS_LONG) {
82            return FAILURE;
83        }
84
85        nest_levels = Z_OP_CONSTANT(opline->op2).value.lval;
86
87        array_offset = Z_OP(opline->op1).opline_num;
88        do {
89            if (array_offset == -1) {
90                return FAILURE;
91            }
92            jmp_to = &op_array->brk_cont_array[array_offset];
93            if (nest_levels > 1) {
94                zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
95
96                switch (brk_opline->opcode) {
97                case ZEND_SWITCH_FREE:
98                case ZEND_FREE:
99#ifdef EXT_TYPE_FREE_ON_RETURN
100                    if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN))
101#endif
102                    {
103                        can_convert = 0;
104                    }
105                    break;
106                }
107            }
108            array_offset = jmp_to->parent;
109        } while (--nest_levels > 0);
110
111        if (can_convert) {
112            /* rewrite to jmp */
113            switch (opline->opcode) {
114            case ZEND_BRK:
115                Z_OP(opline->op1).opline_num = jmp_to->brk;
116                break;
117
118            case ZEND_CONT:
119                Z_OP(opline->op1).opline_num = jmp_to->cont;
120                break;
121            }
122            Z_OP_TYPE(opline->op2) = IS_UNUSED;
123            opline->opcode = ZEND_JMP;
124        }
125    }
126
127    return SUCCESS;
128}
129/* }}} */
130/* {{{ op_flowinfo helper func */
131enum {
132    XC_OPNUM_INVALID = -1
133};
134typedef struct {
135    int       jmpout_op1;
136    int       jmpout_op2;
137    int       jmpout_ext;
138    zend_bool fall;
139} op_flowinfo_t;
140static void op_flowinfo_init(op_flowinfo_t *fi)
141{
142    fi->jmpout_op1 = fi->jmpout_op2 = fi->jmpout_ext = XC_OPNUM_INVALID;
143    fi->fall = 0;
144}
145/* }}} */
146static int op_get_flowinfo(op_flowinfo_t *fi, zend_op *opline) /* {{{ */
147{
148    op_flowinfo_init(fi);
149
150    switch (opline->opcode) {
151#ifdef ZEND_HANDLE_EXCEPTION
152    case ZEND_HANDLE_EXCEPTION:
153#endif
154    case ZEND_RETURN:
155#ifdef ZEND_FAST_RET
156    case ZEND_FAST_RET:
157#endif
158#ifdef ZEND_GENERATOR_RETURN
159    case ZEND_GENERATOR_RETURN:
160#endif
161    case ZEND_EXIT:
162        return SUCCESS; /* no fall */
163
164#ifdef ZEND_GOTO
165    case ZEND_GOTO:
166#endif
167    case ZEND_JMP:
168        fi->jmpout_op1 = Z_OP(opline->op1).opline_num;
169        return SUCCESS; /* no fall */
170
171#ifdef ZEND_FAST_CALL
172    case ZEND_FAST_CALL:
173        fi->jmpout_op1 = Z_OP(opline->op1).opline_num;
174        if (opline->extended_value) {
175            fi->jmpout_op2 = Z_OP(opline->op2).opline_num;
176        }
177        return SUCCESS; /* no fall */
178#endif
179
180    case ZEND_JMPZNZ:
181        fi->jmpout_op2 = Z_OP(opline->op2).opline_num;
182        fi->jmpout_ext = (int) opline->extended_value;
183        return SUCCESS; /* no fall */
184
185    case ZEND_JMPZ:
186    case ZEND_JMPNZ:
187    case ZEND_JMPZ_EX:
188    case ZEND_JMPNZ_EX:
189#ifdef ZEND_JMP_SET
190    case ZEND_JMP_SET:
191#endif
192#ifdef ZEND_JMP_SET_VAR
193    case ZEND_JMP_SET_VAR:
194#endif
195#ifdef ZEND_JMP_NO_CTOR
196    case ZEND_JMP_NO_CTOR:
197#endif
198#ifdef ZEND_NEW
199    case ZEND_NEW:
200#endif
201#ifdef ZEND_FE_RESET
202    case ZEND_FE_RESET:
203#endif     
204    case ZEND_FE_FETCH:
205        fi->jmpout_op2 = Z_OP(opline->op2).opline_num;
206        fi->fall = 1;
207        return SUCCESS;
208
209#ifdef ZEND_CATCH
210    case ZEND_CATCH:
211        fi->jmpout_ext = (int) opline->extended_value;
212        fi->fall = 1;
213        return SUCCESS;
214#endif
215
216    default:
217        return FAILURE;
218    }
219}
220/* }}} */
221#ifdef XCACHE_DEBUG
222static void op_snprint(zend_op_array *op_array, char *buf, int size, zend_uchar op_type, znode_op *op, xc_op_spec_t op_spec) /* {{{ */
223{
224    switch ((op_spec & OPSPEC_UNUSED) ? IS_UNUSED : op_type) {
225    case IS_CONST:
226        {
227            zval result;
228            zval *zv = &Z_OP_CONSTANT(*op);
229            TSRMLS_FETCH();
230
231            php_output_start_default(TSRMLS_C);
232            php_var_export(&zv, 1 TSRMLS_CC);
233            php_output_get_contents(&result TSRMLS_CC); 
234            php_output_discard(TSRMLS_C);
235
236            snprintf(buf, size, Z_STRVAL(result));
237            zval_dtor(&result);
238        }
239        break;
240
241    case IS_TMP_VAR:
242        snprintf(buf, size, "t@%d", Z_OP(*op).var);
243        break;
244
245    case XCACHE_IS_CV:
246    case IS_VAR:
247        snprintf(buf, size, "v@%d", Z_OP(*op).var);
248        break;
249
250    case IS_UNUSED:
251        if (Z_OP(*op).opline_num) {
252            snprintf(buf, size, "u#%d", Z_OP(*op).opline_num);
253        }
254        else {
255            snprintf(buf, size, "-");
256        }
257        break;
258
259    default:
260        snprintf(buf, size, "%d %d", op_type, Z_OP(*op).var);
261    }
262}
263/* }}} */
264static void op_print(zend_op_array *op_array, int line, zend_op *first, zend_op *end) /* {{{ */
265{
266    zend_op *opline;
267    for (opline = first; opline < end; opline ++) {
268        char buf_r[20];
269        char buf_1[20];
270        char buf_2[20];
271        const xc_opcode_spec_t *opcode_spec = xc_get_opcode_spec(opline->opcode);
272        op_snprint(op_array, buf_r, sizeof(buf_r), Z_OP_TYPE(opline->result), &opline->result, opcode_spec->res);
273        op_snprint(op_array, buf_1, sizeof(buf_1), Z_OP_TYPE(opline->op1),    &opline->op1,    opcode_spec->op1);
274        op_snprint(op_array, buf_2, sizeof(buf_2), Z_OP_TYPE(opline->op2),    &opline->op2,    opcode_spec->op2);
275        fprintf(stderr,
276                "%3d %3lu"
277                " %-25s%-8s%-20s%-20s%5lu\n"
278                , opline->lineno, (long) (opline - first + line)
279                , xc_get_opcode(opline->opcode), buf_r, buf_1, buf_2, opline->extended_value);
280    }
281}
282/* }}} */
283static void op_array_print_try_catch(zend_op_array *op_array TSRMLS_DC) /* {{{ */
284{
285    int i;
286    for (i = 0; i < op_array->last_try_catch; i ++) {
287        zend_try_catch_element *element = &op_array->try_catch_array[i];
288#   ifdef ZEND_ENGINE_2_5
289        fprintf(stderr, "try_catch[%d] = %u, %u, %u, %u\n", i, element->try_op, element->catch_op, element->finally_op, element->finally_end);
290#   else
291        fprintf(stderr, "try_catch[%d] = %u, %u\n", i, element->try_op, element->catch_op);
292#   endif
293    }
294}
295/* }}} */
296#endif
297
298/*
299 * basic block functions
300 */
301
302static bb_t *bb_new_ex(zend_op *opcodes, int count) /* {{{ */
303{
304    bb_t *bb = (bb_t *) ecalloc(sizeof(bb_t), 1);
305
306    bb->fall       = BBID_INVALID;
307
308    if (opcodes) {
309        bb->alloc   = 0;
310        bb->size    = bb->count = count;
311        bb->opcodes = opcodes;
312    }
313    else {
314        bb->alloc   = 1;
315        bb->size    = bb->count = 8;
316        bb->opcodes = ecalloc(sizeof(zend_op), bb->size);
317    }
318
319    return bb;
320}
321/* }}} */
322#define bb_new() bb_new_ex(NULL, 0)
323static void bb_destroy(bb_t *bb) /* {{{ */
324{
325    if (bb->alloc) {
326        efree(bb->opcodes);
327    }
328    efree(bb);
329}
330/* }}} */
331#ifdef XCACHE_DEBUG
332static void bb_print(bb_t *bb, zend_op_array *op_array) /* {{{ */
333{
334    int line = bb->opcodes - op_array->opcodes;
335    op_flowinfo_t fi;
336    zend_op *last = bb->opcodes + bb->count - 1;
337
338    op_get_flowinfo(&fi, last);
339
340    fprintf(stderr,
341            "\n==== #%-3d cnt:%-3d lno:%-3d"
342            " %c%c"
343            " op1:%-3d op2:%-3d ext:%-3d fal:%-3d %s ====\n"
344            , bb->id, bb->count, bb->alloc ? -1 : line
345            , bb->used ? 'U' : ' ', bb->alloc ? 'A' : ' '
346            , fi.jmpout_op1, fi.jmpout_op2, fi.jmpout_ext, bb->fall, xc_get_opcode(last->opcode)
347            );
348    op_print(op_array, line, bb->opcodes, last + 1);
349}
350/* }}} */
351#endif
352
353static bb_t *bbs_get(bbs_t *bbs, int n) /* {{{ */
354{
355    return xc_vector_data(bb_t *, bbs)[n];
356}
357/* }}} */
358static int bbs_count(bbs_t *bbs) /* {{{ */
359{
360    return xc_vector_size(bbs);
361}
362/* }}} */
363static void bbs_destroy(bbs_t *bbs TSRMLS_DC) /* {{{ */
364{
365    bb_t *bb;
366    while (bbs_count(bbs)) {
367        bb = xc_vector_pop_back(bb_t *, bbs);
368        bb_destroy(bb);
369    }
370    xc_vector_destroy(bbs);
371}
372/* }}} */
373#ifdef XCACHE_DEBUG
374static void bbs_print(bbs_t *bbs, zend_op_array *op_array) /* {{{ */
375{
376    int i;
377    for (i = 0; i < xc_vector_size(bbs); i ++) {
378        bb_print(bbs_get(bbs, i), op_array);
379    }
380}
381/* }}} */
382#endif
383#define bbs_init(bbs) xc_vector_init(bb_t *, bbs, 0)
384#define bbs_initializer() xc_vector_initializer(bb_t *, 0)
385static bb_t *bbs_add_bb(bbs_t *bbs, bb_t *bb TSRMLS_DC) /* {{{ */
386{
387    bb->id = (bbid_t) bbs_count(bbs);
388    xc_vector_push_back(bbs, &bb);
389    return bb;
390}
391/* }}} */
392static bb_t *bbs_new_bb_ex(bbs_t *bbs, zend_op *opcodes, int count TSRMLS_DC) /* {{{ */
393{
394    return bbs_add_bb(bbs, bb_new_ex(opcodes, count) TSRMLS_CC);
395}
396/* }}} */
397static int bbs_build_from(bbs_t *bbs, zend_op_array *op_array, int count TSRMLS_DC) /* {{{ */
398{
399    int i, start;
400    bb_t *bb;
401    bbid_t id;
402    op_flowinfo_t fi;
403    zend_op *opline;
404    ALLOCA_FLAG(opline_infos_use_heap)
405    typedef struct {
406        zend_bool isbbhead;
407        bbid_t bbid;
408    } oplineinfo_t;
409    oplineinfo_t *oplineinfos = xc_do_alloca(count * sizeof(oplineinfo_t), opline_infos_use_heap);
410
411    memset(oplineinfos, 0, count * sizeof(oplineinfo_t));
412
413    /* {{{ mark jmpin/jumpout */
414    oplineinfos[0].isbbhead = 1;
415    for (i = 0; i < count; i ++) {
416        if (op_get_flowinfo(&fi, &op_array->opcodes[i]) == SUCCESS) {
417            if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
418                oplineinfos[fi.jmpout_op1].isbbhead = 1;
419            }
420            if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
421                oplineinfos[fi.jmpout_op2].isbbhead = 1;
422            }
423            if (fi.jmpout_ext != XC_OPNUM_INVALID) {
424                oplineinfos[fi.jmpout_ext].isbbhead = 1;
425            }
426            if (i + 1 < count) {
427                oplineinfos[i + 1].isbbhead = 1;
428            }
429        }
430    }
431#ifdef ZEND_ENGINE_2
432    /* mark try start */
433    for (i = 0; i < op_array->last_try_catch; i ++) {
434#   define MARK_OP_BB_HEAD(name) \
435        oplineinfos[op_array->try_catch_array[i].name].isbbhead = 1
436        MARK_OP_BB_HEAD(try_op);
437        MARK_OP_BB_HEAD(catch_op);
438#   ifdef ZEND_ENGINE_2_5
439        MARK_OP_BB_HEAD(finally_op);
440#   endif
441#   undef MARK_OP_BB_HEAD
442    }
443#endif
444    /* }}} */
445    /* {{{ fill op lines with newly allocated id */
446    for (i = 0; i < count; i ++) {
447        oplineinfos[i].bbid = BBID_INVALID;
448    }
449
450    id = -1;
451    for (i = 0; i < count; i ++) {
452        if (oplineinfos[i].isbbhead) {
453            id ++;
454        }
455        oplineinfos[i].bbid = id;
456        TRACE("bbids[%d] = %d", i, id);
457    }
458    /* }}} */
459#ifdef ZEND_ENGINE_2
460    /* {{{ convert try_catch_array.* from oplinenum to bbid */
461    for (i = 0; i < op_array->last_try_catch; i ++) {
462#   define OPNUM_TO_BBID(name) \
463        op_array->try_catch_array[i].name = oplineinfos[op_array->try_catch_array[i].name].bbid;
464        OPNUM_TO_BBID(try_op);
465        OPNUM_TO_BBID(catch_op);
466#   ifdef ZEND_ENGINE_2_5
467        OPNUM_TO_BBID(finally_op);
468#   endif
469#   undef OPNUM_TO_BBID
470    }
471    /* }}} */
472#endif
473    /* {{{ create basic blocks */
474    start = 0;
475    id = 0;
476    /* loop over to deal with the last block */
477    for (i = 1; i <= count; i ++) {
478        if (i < count && id == oplineinfos[i].bbid) {
479            continue;
480        }
481
482        opline = op_array->opcodes + start;
483        bb = bbs_new_bb_ex(bbs, opline, i - start TSRMLS_CC);
484
485        /* last */
486        opline = bb->opcodes + bb->count - 1;
487        if (op_get_flowinfo(&fi, opline) == SUCCESS) {
488            if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
489                Z_OP(opline->op1).opline_num = oplineinfos[fi.jmpout_op1].bbid;
490                assert(Z_OP(opline->op1).opline_num != BBID_INVALID);
491            }
492            if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
493                Z_OP(opline->op2).opline_num = oplineinfos[fi.jmpout_op2].bbid;
494                assert(Z_OP(opline->op2).opline_num != BBID_INVALID);
495            }
496            if (fi.jmpout_ext != XC_OPNUM_INVALID) {
497                opline->extended_value = oplineinfos[fi.jmpout_ext].bbid;
498                assert(opline->extended_value != BBID_INVALID);
499            }
500            if (fi.fall && i + 1 < count) {
501                bb->fall = oplineinfos[i + 1].bbid;
502                TRACE("fall %d", bb->fall);
503                assert(bb->fall != BBID_INVALID);
504            }
505        }
506        if (i >= count) {
507            break;
508        }
509        start = i;
510        id = oplineinfos[i].bbid;
511    }
512    /* }}} */
513
514    xc_free_alloca(oplineinfos, opline_infos_use_heap);
515    return SUCCESS;
516}
517/* }}} */
518static void bbs_restore_opnum(bbs_t *bbs, zend_op_array *op_array) /* {{{ */
519{
520    int bbid;
521#ifdef ZEND_ENGINE_2
522    int i;
523#endif
524
525    for (bbid = 0; bbid < bbs_count(bbs); bbid ++) {
526        op_flowinfo_t fi;
527        bb_t *bb = bbs_get(bbs, bbid);
528        zend_op *last = bb->opcodes + bb->count - 1;
529
530        if (op_get_flowinfo(&fi, last) == SUCCESS) {
531            if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
532                Z_OP(last->op1).opline_num = bbs_get(bbs, fi.jmpout_op1)->opnum;
533                assert(Z_OP(last->op1).opline_num != BBID_INVALID);
534            }
535            if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
536                Z_OP(last->op2).opline_num = bbs_get(bbs, fi.jmpout_op2)->opnum;
537                assert(Z_OP(last->op2).opline_num != BBID_INVALID);
538            }
539            if (fi.jmpout_ext != XC_OPNUM_INVALID) {
540                last->extended_value = bbs_get(bbs, fi.jmpout_ext)->opnum;
541                assert(last->extended_value != BBID_INVALID);
542            }
543        }
544    }
545
546#ifdef ZEND_ENGINE_2
547    /* {{{ convert try_catch_array from bbid to oplinenum */
548    for (i = 0; i < op_array->last_try_catch; i ++) {
549#   define BBID_TO_OPNUM(name) \
550        op_array->try_catch_array[i].name = bbs_get(bbs, op_array->try_catch_array[i].name)->opnum;
551        BBID_TO_OPNUM(try_op);
552        BBID_TO_OPNUM(catch_op);
553#   ifdef ZEND_ENGINE_2_5
554        BBID_TO_OPNUM(finally_op);
555#   endif
556#   undef BBID_TO_OPNUM
557    }
558    /* }}} */
559#endif /* ZEND_ENGINE_2 */
560}
561/* }}} */
562
563/*
564 * optimize
565 */
566static int xc_optimize_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
567{
568    if (op_array->type != ZEND_USER_FUNCTION) {
569        return 0;
570    }
571
572#ifdef XCACHE_DEBUG
573    TRACE("optimize file: %s", op_array->filename);
574#   if 0 && HAVE_XCACHE_DPRINT
575    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
576#   endif
577    op_array_print_try_catch(op_array TSRMLS_CC);
578    op_print(op_array, 0, op_array->opcodes, op_array->opcodes + op_array->last);
579#endif
580
581    if (op_array_convert_switch(op_array) == SUCCESS) {
582        bbs_t bbs = bbs_initializer();
583
584        if (bbs_build_from(&bbs, op_array, op_array->last TSRMLS_CC) == SUCCESS) {
585            int i;
586#ifdef XCACHE_DEBUG
587            bbs_print(&bbs, op_array);
588#endif
589            /* TODO: calc opnum after basic block move */
590            for (i = 0; i < bbs_count(&bbs); i ++) {
591                bb_t *bb = bbs_get(&bbs, i);
592                bb->opnum = bb->opcodes - op_array->opcodes;
593            }
594            bbs_restore_opnum(&bbs, op_array);
595        }
596        bbs_destroy(&bbs TSRMLS_CC);
597    }
598
599#ifdef XCACHE_DEBUG
600    TRACE("%s", "after compiles");
601#   if 0
602    xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
603#   endif
604    op_array_print_try_catch(op_array TSRMLS_CC);
605    op_print(op_array, 0, op_array->opcodes, op_array->opcodes + op_array->last);
606#endif
607    return 0;
608}
609/* }}} */
610static void xc_optimizer_op_array_handler(zend_op_array *op_array) /* {{{ */
611{
612    TSRMLS_FETCH();
613    if (XG(optimizer)) {
614        xc_optimize_op_array(op_array TSRMLS_CC);
615    }
616}
617/* }}} */
618
619static int xc_coverager_zend_startup(zend_extension *extension) /* {{{ */
620{
621    return SUCCESS;
622}
623/* }}} */
624static void xc_coverager_zend_shutdown(zend_extension *extension) /* {{{ */
625{
626}
627/* }}} */
628/* {{{ zend extension definition structure */
629static zend_extension xc_optimizer_zend_extension_entry = {
630    XCACHE_NAME " Optimizer",
631    XCACHE_VERSION,
632    XCACHE_AUTHOR,
633    XCACHE_URL,
634    XCACHE_COPYRIGHT,
635    xc_coverager_zend_startup,
636    xc_coverager_zend_shutdown,
637    NULL,           /* activate_func_t */
638    NULL,           /* deactivate_func_t */
639    NULL,           /* message_handler_func_t */
640    xc_optimizer_op_array_handler,
641    NULL,           /* statement_handler_func_t */
642    NULL,           /* fcall_begin_handler_func_t */
643    NULL,           /* fcall_end_handler_func_t */
644    NULL,           /* op_array_ctor_func_t */
645    NULL,           /* op_array_dtor_func_t */
646    STANDARD_ZEND_EXTENSION_PROPERTIES
647};
648/* }}} */
649
650/* {{{ ini */
651PHP_INI_BEGIN()
652    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
653PHP_INI_END()
654/* }}} */
655static PHP_MINFO_FUNCTION(xcache_optimizer) /* {{{ */
656{
657    php_info_print_table_start();
658    php_info_print_table_row(2, "XCache Optimizer Module", "enabled");
659    php_info_print_table_end();
660
661    DISPLAY_INI_ENTRIES();
662}
663/* }}} */
664static PHP_MINIT_FUNCTION(xcache_optimizer) /* {{{ */
665{
666    REGISTER_INI_ENTRIES();
667    return xcache_zend_extension_add(&xc_optimizer_zend_extension_entry, 0);
668}
669/* }}} */
670static PHP_MSHUTDOWN_FUNCTION(xcache_optimizer) /* {{{ */
671{
672    UNREGISTER_INI_ENTRIES();
673    return xcache_zend_extension_remove(&xc_optimizer_zend_extension_entry);
674}
675/* }}} */
676static zend_module_entry xcache_optimizer_module_entry = { /* {{{ */
677    STANDARD_MODULE_HEADER,
678    XCACHE_NAME " Optimizer",
679    NULL,
680    PHP_MINIT(xcache_optimizer),
681    PHP_MSHUTDOWN(xcache_optimizer),
682    NULL,
683    NULL,
684    PHP_MINFO(xcache_optimizer),
685    XCACHE_VERSION,
686#ifdef PHP_GINIT
687    NO_MODULE_GLOBALS,
688#endif
689#ifdef ZEND_ENGINE_2
690    NULL,
691#else
692    NULL,
693    NULL,
694#endif
695    STANDARD_MODULE_PROPERTIES_EX
696};
697/* }}} */
698int xc_optimizer_startup_module() /* {{{ */
699{
700    return zend_startup_module(&xcache_optimizer_module_entry);
701}
702/* }}} */
Note: See TracBrowser for help on using the repository browser.