source: svn/trunk/processor/head.m4 @ 311

Last change on this file since 311 was 311, checked in by Xuefer, 10 years ago

restruct cached compile, add md5 table to recognize and merge file with same content

File size: 11.3 KB
Line 
1dnl {{{ === program start ========================================
2divert(0)
3#include <string.h>
4#include <stdio.h>
5
6#include "php.h"
7#include "zend_extensions.h"
8#include "zend_compile.h"
9#include "zend_API.h"
10#include "zend_ini.h"
11
12#include "xcache.h"
13#include "align.h"
14#include "const_string.h"
15#include "processor.h"
16#include "stack.h"
17#include "xcache_globals.h"
18
19#if defined(HARDENING_PATCH_HASH_PROTECT) && HARDENING_PATCH_HASH_PROTECT
20extern unsigned int zend_hash_canary;
21#endif
22
23define(`SIZEOF_zend_uint', `sizeof(zend_uint)')
24define(`COUNTOF_zend_uint', `1')
25define(`SIZEOF_int', `sizeof(int)')
26define(`COUNTOF_int', `1')
27define(`SIZEOF_zend_function', `sizeof(zend_function)')
28define(`COUNTOF_zend_function', `1')
29define(`SIZEOF_zval_ptr', `sizeof(zval_ptr)')
30define(`COUNTOF_zval_ptr', `1')
31define(`SIZEOF_xc_entry_name_t', `sizeof(xc_entry_name_t)')
32define(`COUNTOF_xc_entry_name_t', `1')
33
34ifdef(`XCACHE_ENABLE_TEST', `
35#undef NDEBUG
36#include <assert.h>
37m4_errprint(`AUTOCHECK INFO: runtime autocheck Enabled (debug build)')
38', `
39m4_errprint(`AUTOCHECK INFO: runtime autocheck Disabled (optimized build)')
40')
41ifdef(`DEBUG_SIZE', `static int xc_totalsize = 0;')
42
43sinclude(builddir`/structinfo.m4')
44
45#ifndef NDEBUG
46#   undef inline
47#define inline
48#endif
49
50typedef zval *zval_ptr;
51typedef zend_uchar zval_data_type;
52#ifdef IS_UNICODE
53typedef UChar zstr_uchar;
54#endif
55typedef char  zstr_char;
56
57#define MAX_DUP_STR_LEN 256
58dnl }}}
59/* export: typedef struct _xc_processor_t xc_processor_t; :export {{{ */
60struct _xc_processor_t {
61    char *p;
62    zend_uint size;
63    HashTable strings;
64    HashTable zvalptrs;
65    zend_bool reference; /* enable if to deal with reference */
66    zend_bool have_references;
67    const xc_entry_data_php_t *php_src;
68    const xc_entry_data_php_t *php_dst;
69    const xc_cache_t          *cache;
70    const zend_class_entry *cache_ce;
71    zend_uint cache_class_num;
72
73    const zend_op          *active_opcodes_src;
74    zend_op                *active_opcodes_dst;
75    const zend_class_entry *active_class_entry_src;
76    zend_class_entry       *active_class_entry_dst;
77    zend_uint               active_class_num;
78
79    zend_bool readonly_protection; /* wheather it's present */
80IFASSERT(xc_stack_t allocsizes;)
81};
82/* }}} */
83#ifdef HAVE_XCACHE_DPRINT
84static void xc_dprint_indent(int indent) /* {{{ */
85{
86    int i;
87    for (i = 0; i < indent; i ++) {
88        fprintf(stderr, "  ");
89    }
90}
91/* }}} */
92static void xc_dprint_str_len(const char *str, int len) /* {{{ */
93{
94    const unsigned char *p = (const unsigned char *) str;
95    int i;
96    for (i = 0; i < len; i ++) {
97        if (p[i] < 32 || p[i] == 127) {
98            fprintf(stderr, "\\%03o", (unsigned int) p[i]);
99        }
100        else {
101            fputc(p[i], stderr);
102        }
103    }
104}
105/* }}} */
106#endif
107/* {{{ xc_zstrlen_char */
108static inline int xc_zstrlen_char(zstr s)
109{
110    return strlen(ZSTR_S(s));
111}
112/* }}} */
113#ifdef IS_UNICODE
114/* {{{ xc_zstrlen_uchar */
115static inline int xc_zstrlen_uchar(zstr s)
116{
117    int i;
118    UChar *p = ZSTR_U(s);
119    for (i = 0; *p; i ++, p++) {
120        /* empty */
121    }
122    return i;
123}
124/* }}} */
125/* {{{ xc_zstrlen */
126static inline int xc_zstrlen(int type, zstr s)
127{
128    return type == IS_UNICODE ? xc_zstrlen_uchar(s) : xc_zstrlen_char(s);
129}
130/* }}} */
131#else
132/* {{{ xc_zstrlen */
133#define xc_zstrlen(dummy, s) xc_zstrlen_char(s)
134/* }}} */
135#endif
136/* {{{ xc_calc_string_n */
137REDEF(`KIND', `calc')
138static inline void xc_calc_string_n(xc_processor_t *processor, zend_uchar type, zstr str, long size IFASSERT(`, int relayline')) {
139    pushdef(`__LINE__', `relayline')
140    int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
141    long dummy = 1;
142
143    if (realsize > MAX_DUP_STR_LEN) {
144        ALLOC(, char, realsize)
145    }
146    else if (zend_u_hash_add(&processor->strings, type, str, size, (void *) &dummy, sizeof(dummy), NULL) == SUCCESS) {
147        /* new string */
148        ALLOC(, char, realsize)
149    }
150    IFASSERT(`
151        else {
152            dnl fprintf(stderr, "dupstr %s\n", ZSTR_S(str));
153        }
154    ')
155    popdef(`__LINE__')
156}
157/* }}} */
158/* {{{ xc_store_string_n */
159REDEF(`KIND', `store')
160static inline zstr xc_store_string_n(xc_processor_t *processor, zend_uchar type, zstr str, long size IFASSERT(`, int relayline')) {
161    pushdef(`__LINE__', `relayline')
162    int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
163    zstr ret, *pret;
164
165    if (realsize > MAX_DUP_STR_LEN) {
166        ALLOC(ZSTR_V(ret), char, realsize)
167        memcpy(ZSTR_V(ret), ZSTR_V(str), realsize);
168        return ret;
169    }
170
171    if (zend_u_hash_find(&processor->strings, type, str, size, (void **) &pret) == SUCCESS) {
172        return *pret;
173    }
174
175    /* new string */
176    ALLOC(ZSTR_V(ret), char, realsize)
177    memcpy(ZSTR_V(ret), ZSTR_V(str), realsize);
178    zend_u_hash_add(&processor->strings, type, str, size, (void *) &ret, sizeof(zstr), NULL);
179    return ret;
180
181    popdef(`__LINE__')
182}
183/* }}} */
184/* {{{ xc_get_class_num
185 * return class_index + 1
186 */
187static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry *ce) {
188    zend_ulong i;
189    const xc_entry_data_php_t *php = processor->php_src;
190    zend_class_entry *ceptr;
191
192    if (processor->cache_ce == ce) {
193        return processor->cache_class_num;
194    }
195    for (i = 0; i < php->classinfo_cnt; i ++) {
196        ceptr = CestToCePtr(php->classinfos[i].cest);
197        if (ZCEP_REFCOUNT_PTR(ceptr) == ZCEP_REFCOUNT_PTR(ce)) {
198            processor->cache_ce = ceptr;
199            processor->cache_class_num = i + 1;
200            return i + 1;
201        }
202    }
203    assert(0);
204    return (zend_ulong) -1;
205}
206/* }}} */
207/* {{{ xc_get_class */
208#ifdef ZEND_ENGINE_2
209static zend_class_entry *xc_get_class(xc_processor_t *processor, zend_ulong class_num) {
210    /* must be parent or currrent class */
211    assert(class_num <= processor->active_class_num);
212    return CestToCePtr(processor->php_dst->classinfos[class_num - 1].cest);
213}
214#endif
215/* }}} */
216#ifdef ZEND_ENGINE_2
217/* fix method on store */
218static void xc_fix_method(xc_processor_t *processor, zend_op_array *dst) /* {{{ */
219{
220    zend_function *zf = (zend_function *) dst;
221    zend_class_entry *ce = processor->active_class_entry_dst;
222
223    /* Fixing up the default functions for objects here since
224     * we need to compare with the newly allocated functions
225     *
226     * caveat: a sub-class method can have the same name as the
227     * parent~s constructor and create problems.
228     */
229
230    if (zf->common.fn_flags & ZEND_ACC_CTOR) {
231        if (!ce->constructor) {
232            ce->constructor = zf;
233        }
234    }
235    else if (zf->common.fn_flags & ZEND_ACC_DTOR) {
236        ce->destructor = zf;
237    }
238    else if (zf->common.fn_flags & ZEND_ACC_CLONE) {
239        ce->clone = zf;
240    }
241    else {
242dnl FIXME: handle common.function_name here
243#define SET_IF_SAME_NAME(member) \
244        do { \
245            if (!strcasecmp(ZSTR_S(zf->common.function_name), #member)) { \
246                ce->member = zf; \
247            } \
248        } \
249        while(0)
250        /* if(ce->member && !strcmp(zf->common.function_name, ce->member->common.function_name)) { \ */
251
252        SET_IF_SAME_NAME(__get);
253        SET_IF_SAME_NAME(__set);
254#ifdef ZEND_ENGINE_2_1
255        SET_IF_SAME_NAME(__unset);
256        SET_IF_SAME_NAME(__isset);
257#endif
258        SET_IF_SAME_NAME(__call);
259#if defined(ZEND_ENGINE_2_2) || PHP_MAJOR_VERSION >= 6
260        SET_IF_SAME_NAME(__tostring);
261#endif
262
263#undef SET_IF_SAME_NAME
264    }
265}
266/* }}} */
267#endif
268/* {{{ call op_array ctor handler */
269extern zend_bool xc_have_op_array_ctor;
270static void xc_zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
271{
272    if (extension->op_array_ctor) {
273        extension->op_array_ctor(op_array);
274    }
275}
276/* }}} */
277dnl ================ export API
278define(`DEFINE_STORE_API', `
279/* export: $1 *xc_processor_store_$1($1 *src TSRMLS_DC); :export {{{ */
280$1 *xc_processor_store_$1($1 *src TSRMLS_DC) {
281    $1 *dst;
282    xc_processor_t processor;
283
284    memset(&processor, 0, sizeof(processor));
285    processor.reference = 1;
286    processor.cache = src->cache;
287
288    IFASSERT(`xc_stack_init(&processor.allocsizes);')
289
290    /* calc size */ {
291        zend_hash_init(&processor.strings, 0, NULL, NULL, 0);
292        if (processor.reference) {
293            zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
294        }
295
296        processor.size = 0;
297        /* allocate */
298        processor.size = ALIGN(processor.size + sizeof(src[0]));
299
300        xc_calc_$1(&processor, src TSRMLS_CC);
301        if (processor.reference) {
302            zend_hash_destroy(&processor.zvalptrs);
303        }
304        zend_hash_destroy(&processor.strings);
305    }
306    src->size = processor.size;
307    ifelse(`$1', `xc_entry_t', `
308        src->data.var->have_references = processor.have_references;
309    ', `
310        src->have_references = processor.have_references;
311    ')
312
313    IFASSERT(`xc_stack_reverse(&processor.allocsizes);')
314    /* store {{{ */
315    {
316        IFASSERT(`char *oldp;')
317        zend_hash_init(&processor.strings, 0, NULL, NULL, 0);
318        if (processor.reference) {
319            zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
320        }
321
322        /* mem :) */
323        processor.p = (char *) processor.cache->mem->handlers->malloc(processor.cache->mem, processor.size);
324        if (processor.p == NULL) {
325            dst = NULL;
326            goto err_alloc;
327        }
328        IFASSERT(`oldp = processor.p;')
329        assert(processor.p == (char *) ALIGN(processor.p));
330
331        /* allocate */
332        dst = ($1 *) processor.p;
333        processor.p = (char *) ALIGN(processor.p + sizeof(dst[0]));
334
335        xc_store_$1(&processor, dst, src TSRMLS_CC);
336        IFASSERT(` {
337            int real = processor.p - oldp;
338            int should = processor.size;
339            if (real != processor.size) {
340                fprintf(stderr, "real %d - should %d = %d\n", real, should, real - should);
341                abort();
342            }
343        }')
344err_alloc:
345        if (processor.reference) {
346            zend_hash_destroy(&processor.zvalptrs);
347        }
348        zend_hash_destroy(&processor.strings);
349    }
350    /* }}} */
351
352    IFASSERT(`xc_stack_destroy(&processor.allocsizes);')
353
354    return dst;
355}
356/* }}} */
357')
358DEFINE_STORE_API(`xc_entry_t')
359DEFINE_STORE_API(`xc_entry_data_php_t')
360/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC); :export {{{ */
361xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC) {
362    xc_processor_t processor;
363
364    memset(&processor, 0, sizeof(processor));
365    xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);
366
367    return dst;
368}
369/* }}} */
370/* export: xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
371xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC) {
372    xc_processor_t processor;
373
374    memset(&processor, 0, sizeof(processor));
375    processor.readonly_protection = readonly_protection;
376    /* this function is used for php data only */
377    if (src->have_references) {
378        processor.reference = 1;
379    }
380
381    if (processor.reference) {
382        zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
383    }
384    xc_restore_xc_entry_data_php_t(&processor, dst, src TSRMLS_CC);
385    if (processor.reference) {
386        zend_hash_destroy(&processor.zvalptrs);
387    }
388    return dst;
389}
390/* }}} */
391/* export: zval *xc_processor_restore_zval(zval *dst, const zval *src, zend_bool have_references TSRMLS_DC); :export {{{ */
392zval *xc_processor_restore_zval(zval *dst, const zval *src, zend_bool have_references TSRMLS_DC) {
393    xc_processor_t processor;
394
395    memset(&processor, 0, sizeof(processor));
396    processor.reference = have_references;
397
398    if (processor.reference) {
399        zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
400        dnl fprintf(stderr, "mark[%p] = %p\n", src, dst);
401        zend_hash_add(&processor.zvalptrs, (char *)src, sizeof(src), (void*)&dst, sizeof(dst), NULL);
402    }
403    xc_restore_zval(&processor, dst, src TSRMLS_CC);
404    if (processor.reference) {
405        zend_hash_destroy(&processor.zvalptrs);
406    }
407
408    return dst;
409}
410/* }}} */
411/* export: void xc_dprint(xc_entry_t *src, int indent TSRMLS_DC); :export {{{ */
412#ifdef HAVE_XCACHE_DPRINT
413void xc_dprint(xc_entry_t *src, int indent TSRMLS_DC) {
414    IFDPRINT(`INDENT()`'fprintf(stderr, "xc_entry_t:src");')
415    xc_dprint_xc_entry_t(src, indent TSRMLS_CC);
416}
417#endif
418/* }}} */
Note: See TracBrowser for help on using the repository browser.