1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#include <zend_language_parser.h>
23#include "zend.h"
24#include "zend_compile.h"
25#include "zend_constants.h"
26#include "zend_llist.h"
27#include "zend_API.h"
28#include "zend_exceptions.h"
29#include "tsrm_virtual_cwd.h"
30#include "zend_multibyte.h"
31#include "zend_language_scanner.h"
32
33#define CONSTANT_EX(op_array, op) \
34    (op_array)->literals[op].constant
35
36#define CONSTANT(op) \
37    CONSTANT_EX(CG(active_op_array), op)
38
39#define SET_NODE(target, src) do { \
40        target ## _type = (src)->op_type; \
41        if ((src)->op_type == IS_CONST) { \
42            target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); \
43        } else { \
44            target = (src)->u.op; \
45        } \
46    } while (0)
47
48#define GET_NODE(target, src) do { \
49        (target)->op_type = src ## _type; \
50        if ((target)->op_type == IS_CONST) { \
51            (target)->u.constant = CONSTANT(src.constant); \
52        } else { \
53            (target)->u.op = src; \
54            (target)->EA = 0; \
55        } \
56    } while (0)
57
58#define COPY_NODE(target, src) do { \
59        target ## _type = src ## _type; \
60        target = src; \
61    } while (0)
62
63#define CALCULATE_LITERAL_HASH(num) do { \
64        if (IS_INTERNED(Z_STRVAL(CONSTANT(num)))) { \
65            Z_HASH_P(&CONSTANT(num)) = INTERNED_HASH(Z_STRVAL(CONSTANT(num))); \
66        } else { \
67            Z_HASH_P(&CONSTANT(num)) = zend_hash_func(Z_STRVAL(CONSTANT(num)), Z_STRLEN(CONSTANT(num))+1); \
68        } \
69    } while (0)
70
71#define GET_CACHE_SLOT(literal) do { \
72        CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot++; \
73        if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \
74            CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \
75            CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \
76        } \
77    } while (0)
78
79#define POLYMORPHIC_CACHE_SLOT_SIZE 2
80
81#define GET_POLYMORPHIC_CACHE_SLOT(literal) do { \
82        CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot; \
83        CG(active_op_array)->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE; \
84        if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \
85            CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \
86            CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \
87            CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 2] = NULL; \
88        } \
89    } while (0)
90
91#define FREE_POLYMORPHIC_CACHE_SLOT(literal) do { \
92        if (CG(active_op_array)->literals[literal].cache_slot != -1 && \
93            CG(active_op_array)->literals[literal].cache_slot == \
94            CG(active_op_array)->last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE) { \
95            CG(active_op_array)->literals[literal].cache_slot = -1; \
96            CG(active_op_array)->last_cache_slot -= POLYMORPHIC_CACHE_SLOT_SIZE; \
97        } \
98    } while (0)
99
100ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
101ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
102
103#ifndef ZTS
104ZEND_API zend_compiler_globals compiler_globals;
105ZEND_API zend_executor_globals executor_globals;
106#endif
107
108static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
109{
110    if (!IS_INTERNED(property_info->name)) {
111        property_info->name = estrndup(property_info->name, property_info->name_length);
112    }
113    if (property_info->doc_comment) {
114        property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len);
115    }
116}
117/* }}} */
118
119static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
120{
121    if (!IS_INTERNED(property_info->name)) {
122        property_info->name = zend_strndup(property_info->name, property_info->name_length);
123    }
124}
125/* }}} */
126
127static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ */
128{
129    str_efree(property_info->name);
130    if (property_info->doc_comment) {
131        efree((char*)property_info->doc_comment);
132    }
133}
134/* }}} */
135
136static void zend_destroy_property_info_internal(zend_property_info *property_info) /* {{{ */
137{
138    str_free((char*)property_info->name);
139}
140/* }}} */
141
142static void build_runtime_defined_function_key(zval *result, const char *name, int name_length TSRMLS_DC) /* {{{ */
143{
144    char char_pos_buf[32];
145    uint char_pos_len;
146    const char *filename;
147
148    char_pos_len = zend_sprintf(char_pos_buf, "%p", LANG_SCNG(yy_text));
149    if (CG(active_op_array)->filename) {
150        filename = CG(active_op_array)->filename;
151    } else {
152        filename = "-";
153    }
154
155    /* NULL, name length, filename length, last accepting char position length */
156    result->value.str.len = 1+name_length+strlen(filename)+char_pos_len;
157
158    /* must be binary safe */
159    result->value.str.val = (char *) safe_emalloc(result->value.str.len, 1, 1);
160    result->value.str.val[0] = '\0';
161    sprintf(result->value.str.val+1, "%s%s%s", name, filename, char_pos_buf);
162
163    result->type = IS_STRING;
164    Z_SET_REFCOUNT_P(result, 1);
165}
166/* }}} */
167
168static void init_compiler_declarables(TSRMLS_D) /* {{{ */
169{
170    Z_TYPE(CG(declarables).ticks) = IS_LONG;
171    Z_LVAL(CG(declarables).ticks) = 0;
172}
173/* }}} */
174
175void zend_init_compiler_context(TSRMLS_D) /* {{{ */
176{
177    CG(context).opcodes_size = (CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) ? INITIAL_INTERACTIVE_OP_ARRAY_SIZE : INITIAL_OP_ARRAY_SIZE;
178    CG(context).vars_size = 0;
179    CG(context).literals_size = 0;
180    CG(context).current_brk_cont = -1;
181    CG(context).backpatch_count = 0;
182    CG(context).nested_calls = 0;
183    CG(context).used_stack = 0;
184    CG(context).in_finally = 0;
185    CG(context).labels = NULL;
186}
187/* }}} */
188
189void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
190{
191    zend_stack_init(&CG(bp_stack));
192    zend_stack_init(&CG(function_call_stack));
193    zend_stack_init(&CG(switch_cond_stack));
194    zend_stack_init(&CG(foreach_copy_stack));
195    zend_stack_init(&CG(object_stack));
196    zend_stack_init(&CG(declare_stack));
197    CG(active_class_entry) = NULL;
198    zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
199    zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
200    zend_stack_init(&CG(list_stack));
201    CG(in_compilation) = 0;
202    CG(start_lineno) = 0;
203    CG(current_namespace) = NULL;
204    CG(in_namespace) = 0;
205    CG(has_bracketed_namespaces) = 0;
206    CG(current_import) = NULL;
207    init_compiler_declarables(TSRMLS_C);
208    zend_stack_init(&CG(context_stack));
209
210    CG(encoding_declared) = 0;
211}
212/* }}} */
213
214ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */
215{
216    TSRMLS_FETCH();
217
218    zend_file_handle_dtor(fh TSRMLS_CC);
219}
220/* }}} */
221
222void init_compiler(TSRMLS_D) /* {{{ */
223{
224    CG(active_op_array) = NULL;
225    memset(&CG(context), 0, sizeof(CG(context)));
226    zend_init_compiler_data_structures(TSRMLS_C);
227    zend_init_rsrc_list(TSRMLS_C);
228    zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0);
229    zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0);
230    CG(unclean_shutdown) = 0;
231}
232/* }}} */
233
234void shutdown_compiler(TSRMLS_D) /* {{{ */
235{
236    zend_stack_destroy(&CG(bp_stack));
237    zend_stack_destroy(&CG(function_call_stack));
238    zend_stack_destroy(&CG(switch_cond_stack));
239    zend_stack_destroy(&CG(foreach_copy_stack));
240    zend_stack_destroy(&CG(object_stack));
241    zend_stack_destroy(&CG(declare_stack));
242    zend_stack_destroy(&CG(list_stack));
243    zend_hash_destroy(&CG(filenames_table));
244    zend_llist_destroy(&CG(open_files));
245    zend_stack_destroy(&CG(context_stack));
246}
247/* }}} */
248
249ZEND_API char *zend_set_compiled_filename(const char *new_compiled_filename TSRMLS_DC) /* {{{ */
250{
251    char **pp, *p;
252    int length = strlen(new_compiled_filename);
253
254    if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) {
255        CG(compiled_filename) = *pp;
256        return *pp;
257    }
258    p = estrndup(new_compiled_filename, length);
259    zend_hash_update(&CG(filenames_table), new_compiled_filename, length+1, &p, sizeof(char *), (void **) &pp);
260    CG(compiled_filename) = p;
261    return p;
262}
263/* }}} */
264
265ZEND_API void zend_restore_compiled_filename(char *original_compiled_filename TSRMLS_DC) /* {{{ */
266{
267    CG(compiled_filename) = original_compiled_filename;
268}
269/* }}} */
270
271ZEND_API char *zend_get_compiled_filename(TSRMLS_D) /* {{{ */
272{
273    return CG(compiled_filename);
274}
275/* }}} */
276
277ZEND_API int zend_get_compiled_lineno(TSRMLS_D) /* {{{ */
278{
279    return CG(zend_lineno);
280}
281/* }}} */
282
283ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */
284{
285    return CG(in_compilation);
286}
287/* }}} */
288
289static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */
290{
291    return (zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, (op_array->T)++);
292}
293/* }}} */
294
295static int lookup_cv(zend_op_array *op_array, char* name, int name_len, ulong hash TSRMLS_DC) /* {{{ */
296{
297    int i = 0;
298    ulong hash_value = hash ? hash : zend_inline_hash_func(name, name_len+1);
299
300    while (i < op_array->last_var) {
301        if (op_array->vars[i].name == name ||
302            (op_array->vars[i].hash_value == hash_value &&
303             op_array->vars[i].name_len == name_len &&
304             memcmp(op_array->vars[i].name, name, name_len) == 0)) {
305            str_efree(name);
306            return i;
307        }
308        i++;
309    }
310    i = op_array->last_var;
311    op_array->last_var++;
312    if (op_array->last_var > CG(context).vars_size) {
313        CG(context).vars_size += 16; /* FIXME */
314        op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_compiled_variable));
315    }
316    op_array->vars[i].name = zend_new_interned_string(name, name_len + 1, 1 TSRMLS_CC);
317    op_array->vars[i].name_len = name_len;
318    op_array->vars[i].hash_value = hash_value;
319    return i;
320}
321/* }}} */
322
323void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */
324{
325    zval_dtor(&CONSTANT_EX(op_array, n));
326    if (n + 1 == op_array->last_literal) {
327        op_array->last_literal--;
328    } else {
329        Z_TYPE(CONSTANT_EX(op_array, n)) = IS_NULL;
330    }
331}
332/* }}} */
333
334/* Common part of zend_add_literal and zend_append_individual_literal */
335static inline void zend_insert_literal(zend_op_array *op_array, const zval *zv, int literal_position TSRMLS_DC) /* {{{ */
336{
337    if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) {
338        zval *z = (zval*)zv;
339        Z_STRVAL_P(z) = (char*)zend_new_interned_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1, 1 TSRMLS_CC);
340    }
341    CONSTANT_EX(op_array, literal_position) = *zv;
342    Z_SET_REFCOUNT(CONSTANT_EX(op_array, literal_position), 2);
343    Z_SET_ISREF(CONSTANT_EX(op_array, literal_position));
344    op_array->literals[literal_position].hash_value = 0;
345    op_array->literals[literal_position].cache_slot = -1;
346}
347/* }}} */
348
349/* Is used while compiling a function, using the context to keep track
350   of an approximate size to avoid to relocate to often.
351   Literals are truncated to actual size in the second compiler pass (pass_two()). */
352int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
353{
354    int i = op_array->last_literal;
355    op_array->last_literal++;
356    if (i >= CG(context).literals_size) {
357        while (i >= CG(context).literals_size) {
358            CG(context).literals_size += 16; /* FIXME */
359        }
360        op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));
361    }
362    zend_insert_literal(op_array, zv, i TSRMLS_CC);
363    return i;
364}
365/* }}} */
366
367/* Is used after normal compilation to append an additional literal.
368   Allocation is done precisely here. */
369int zend_append_individual_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
370{
371    int i = op_array->last_literal;
372    op_array->last_literal++;
373    op_array->literals = (zend_literal*)erealloc(op_array->literals, (i + 1) * sizeof(zend_literal));
374    zend_insert_literal(op_array, zv, i TSRMLS_CC);
375    return i;
376}
377/* }}} */
378
379int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
380{
381    int ret;
382    char *lc_name;
383    zval c;
384    int lc_literal;
385
386    if (op_array->last_literal > 0 &&
387        &op_array->literals[op_array->last_literal - 1].constant == zv &&
388        op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
389        /* we already have function name as last literal (do nothing) */
390        ret = op_array->last_literal - 1;
391    } else {
392        ret = zend_add_literal(op_array, zv TSRMLS_CC);
393    }
394
395    lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
396    ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
397    lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
398    CALCULATE_LITERAL_HASH(lc_literal);
399
400    return ret;
401}
402/* }}} */
403
404int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
405{
406    int ret;
407    char *lc_name;
408    const char *ns_separator;
409    int lc_len;
410    zval c;
411    int lc_literal;
412
413    if (op_array->last_literal > 0 &&
414        &op_array->literals[op_array->last_literal - 1].constant == zv &&
415        op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
416        /* we already have function name as last literal (do nothing) */
417        ret = op_array->last_literal - 1;
418    } else {
419        ret = zend_add_literal(op_array, zv TSRMLS_CC);
420    }
421
422    lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
423    ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
424    lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
425    CALCULATE_LITERAL_HASH(lc_literal);
426
427    ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)) + 1;
428    lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv));
429    lc_name = zend_str_tolower_dup(ns_separator, lc_len);
430    ZVAL_STRINGL(&c, lc_name, lc_len, 0);
431    lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
432    CALCULATE_LITERAL_HASH(lc_literal);
433
434    return ret;
435}
436/* }}} */
437
438int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
439{
440    int ret;
441    char *lc_name;
442    int lc_len;
443    zval c;
444    int lc_literal;
445
446    if (op_array->last_literal > 0 &&
447        &op_array->literals[op_array->last_literal - 1].constant == zv &&
448        op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
449        /* we already have function name as last literal (do nothing) */
450        ret = op_array->last_literal - 1;
451    } else {
452        ret = zend_add_literal(op_array, zv TSRMLS_CC);
453    }
454
455    if (Z_STRVAL_P(zv)[0] == '\\') {
456        lc_len = Z_STRLEN_P(zv) - 1;
457        lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv) + 1, lc_len);
458    } else {
459        lc_len = Z_STRLEN_P(zv);
460        lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), lc_len);
461    }
462    ZVAL_STRINGL(&c, lc_name, lc_len, 0);
463    lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
464    CALCULATE_LITERAL_HASH(lc_literal);
465
466    GET_CACHE_SLOT(ret);
467
468    return ret;
469}
470/* }}} */
471
472int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unqualified TSRMLS_DC) /* {{{ */
473{
474    int ret, tmp_literal;
475    char *name, *tmp_name;
476    const char *ns_separator;
477    int name_len, ns_len;
478    zval c;
479
480    if (op_array->last_literal > 0 &&
481        &op_array->literals[op_array->last_literal - 1].constant == zv &&
482        op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
483        /* we already have function name as last literal (do nothing) */
484        ret = op_array->last_literal - 1;
485    } else {
486        ret = zend_add_literal(op_array, zv TSRMLS_CC);
487    }
488
489    /* skip leading '\\' */
490    if (Z_STRVAL_P(zv)[0] == '\\') {
491        name_len = Z_STRLEN_P(zv) - 1;
492        name = Z_STRVAL_P(zv) + 1;
493    } else {
494        name_len = Z_STRLEN_P(zv);
495        name = Z_STRVAL_P(zv);
496    }
497    ns_separator = zend_memrchr(name, '\\', name_len);
498    if (ns_separator) {
499        ns_len = ns_separator - name;
500    } else {
501        ns_len = 0;
502    }
503
504    if (ns_len) {
505        /* lowercased namespace name & original constant name */
506        tmp_name = estrndup(name, name_len);
507        zend_str_tolower(tmp_name, ns_len);
508        ZVAL_STRINGL(&c, tmp_name, name_len, 0);
509        tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
510        CALCULATE_LITERAL_HASH(tmp_literal);
511
512        /* lowercased namespace name & lowercased constant name */
513        tmp_name = zend_str_tolower_dup(name, name_len);
514        ZVAL_STRINGL(&c, tmp_name, name_len, 0);
515        tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
516        CALCULATE_LITERAL_HASH(tmp_literal);
517    }
518
519    if (ns_len) {
520        if (!unqualified) {
521            return ret;
522        }
523        ns_len++;
524        name += ns_len;
525        name_len -= ns_len;
526    }
527
528    /* original constant name */
529    tmp_name = estrndup(name, name_len);
530    ZVAL_STRINGL(&c, tmp_name, name_len, 0);
531    tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
532    CALCULATE_LITERAL_HASH(tmp_literal);
533
534    /* lowercased constant name */
535    tmp_name = zend_str_tolower_dup(name, name_len);
536    ZVAL_STRINGL(&c, tmp_name, name_len, 0);
537    tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
538    CALCULATE_LITERAL_HASH(tmp_literal);
539
540    return ret;
541}
542/* }}} */
543
544#define LITERAL_STRINGL(op, str, len, copy) do { \
545        zval _c; \
546        ZVAL_STRINGL(&_c, str, len, copy); \
547        op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
548    } while (0)
549
550#define LITERAL_LONG(op, val) do { \
551        zval _c; \
552        ZVAL_LONG(&_c, val); \
553        op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
554    } while (0)
555
556#define LITERAL_LONG_EX(op_array, op, val) do { \
557        zval _c; \
558        ZVAL_LONG(&_c, val); \
559        op.constant = zend_add_literal(op_array, &_c TSRMLS_CC); \
560    } while (0)
561
562#define LITERAL_NULL(op) do { \
563        zval _c; \
564        INIT_ZVAL(  _c); \
565        op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
566    } while (0)
567
568static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */
569{
570    zend_uint type = variable->EA;
571
572    return  ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
573}
574/* }}} */
575
576void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
577{
578    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
579
580    opline->opcode = op;
581    opline->result_type = IS_TMP_VAR;
582    opline->result.var = get_temporary_variable(CG(active_op_array));
583    SET_NODE(opline->op1, op1);
584    SET_NODE(opline->op2, op2);
585    GET_NODE(result, opline->result);
586}
587/* }}} */
588
589void zend_do_unary_op(zend_uchar op, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */
590{
591    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
592
593    opline->opcode = op;
594    opline->result_type = IS_TMP_VAR;
595    opline->result.var = get_temporary_variable(CG(active_op_array));
596    SET_NODE(opline->op1, op1);
597    GET_NODE(result, opline->result);
598    SET_UNUSED(opline->op2);
599}
600/* }}} */
601
602#define MAKE_NOP(opline)    { opline->opcode = ZEND_NOP;  memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED;  }
603
604static void zend_do_op_data(zend_op *data_op, const znode *value TSRMLS_DC) /* {{{ */
605{
606    data_op->opcode = ZEND_OP_DATA;
607    SET_NODE(data_op->op1, value);
608    SET_UNUSED(data_op->op2);
609}
610/* }}} */
611
612void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
613{
614    int last_op_number = get_next_op_number(CG(active_op_array));
615    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
616
617    if (last_op_number > 0) {
618        zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
619
620        switch (last_op->opcode) {
621            case ZEND_FETCH_OBJ_RW:
622                last_op->opcode = op;
623                last_op->extended_value = ZEND_ASSIGN_OBJ;
624
625                zend_do_op_data(opline, op2 TSRMLS_CC);
626                SET_UNUSED(opline->result);
627                GET_NODE(result, last_op->result);
628                return;
629            case ZEND_FETCH_DIM_RW:
630                last_op->opcode = op;
631                last_op->extended_value = ZEND_ASSIGN_DIM;
632
633                zend_do_op_data(opline, op2 TSRMLS_CC);
634                opline->op2.var = get_temporary_variable(CG(active_op_array));
635                opline->op2_type = IS_VAR;
636                SET_UNUSED(opline->result);
637                GET_NODE(result,last_op->result);
638                return;
639            default:
640                break;
641        }
642    }
643
644    opline->opcode = op;
645    SET_NODE(opline->op1, op1);
646    SET_NODE(opline->op2, op2);
647    opline->result_type = IS_VAR;
648    opline->result.var = get_temporary_variable(CG(active_op_array));
649    GET_NODE(result, opline->result);
650}
651/* }}} */
652
653void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC) /* {{{ */
654{
655    zend_op opline;
656    zend_op *opline_ptr;
657    zend_llist *fetch_list_ptr;
658
659    if (varname->op_type == IS_CONST) {
660        ulong hash = 0;
661
662        if (Z_TYPE(varname->u.constant) != IS_STRING) {
663            convert_to_string(&varname->u.constant);
664        } else if (IS_INTERNED(Z_STRVAL(varname->u.constant))) {
665            hash = INTERNED_HASH(Z_STRVAL(varname->u.constant));
666        }
667        if (!zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC) &&
668            !(varname->u.constant.value.str.len == (sizeof("this")-1) &&
669              !memcmp(varname->u.constant.value.str.val, "this", sizeof("this"))) &&
670            (CG(active_op_array)->last == 0 ||
671             CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) {
672            result->op_type = IS_CV;
673            result->u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC);
674            varname->u.constant.value.str.val = (char*)CG(active_op_array)->vars[result->u.op.var].name;
675            result->EA = 0;
676            return;
677        }
678    }
679
680    if (bp) {
681        opline_ptr = &opline;
682        init_op(opline_ptr TSRMLS_CC);
683    } else {
684        opline_ptr = get_next_op(CG(active_op_array) TSRMLS_CC);
685    }
686
687    opline_ptr->opcode = op;
688    opline_ptr->result_type = IS_VAR;
689    opline_ptr->result.var = get_temporary_variable(CG(active_op_array));
690    SET_NODE(opline_ptr->op1, varname);
691    GET_NODE(result, opline_ptr->result);
692    SET_UNUSED(opline_ptr->op2);
693    opline_ptr->extended_value = ZEND_FETCH_LOCAL;
694
695    if (varname->op_type == IS_CONST) {
696        CALCULATE_LITERAL_HASH(opline_ptr->op1.constant);
697        if (zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC)) {
698            opline_ptr->extended_value = ZEND_FETCH_GLOBAL;
699        }
700    }
701
702    if (bp) {
703        zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
704        zend_llist_add_element(fetch_list_ptr, opline_ptr);
705    }
706}
707/* }}} */
708
709void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* {{{ */
710{
711    /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
712    fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W TSRMLS_CC);
713}
714/* }}} */
715
716void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
717{
718    znode class_node;
719    zend_llist *fetch_list_ptr;
720    zend_llist_element *le;
721    zend_op *opline_ptr;
722    zend_op opline;
723
724    if (class_name->op_type == IS_CONST &&
725        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
726        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
727        class_node = *class_name;
728    } else {
729        zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
730    }
731    zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
732    if (result->op_type == IS_CV) {
733        init_op(&opline TSRMLS_CC);
734
735        opline.opcode = ZEND_FETCH_W;
736        opline.result_type = IS_VAR;
737        opline.result.var = get_temporary_variable(CG(active_op_array));
738        opline.op1_type = IS_CONST;
739        LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0);
740        CALCULATE_LITERAL_HASH(opline.op1.constant);
741        GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
742        if (class_node.op_type == IS_CONST) {
743            opline.op2_type = IS_CONST;
744            opline.op2.constant =
745                zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
746        } else {
747            SET_NODE(opline.op2, &class_node);
748        }
749        GET_NODE(result,opline.result);
750        opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
751        opline_ptr = &opline;
752
753        zend_llist_add_element(fetch_list_ptr, &opline);
754    } else {
755        le = fetch_list_ptr->head;
756
757        opline_ptr = (zend_op *)le->data;
758        if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) {
759            init_op(&opline TSRMLS_CC);
760            opline.opcode = ZEND_FETCH_W;
761            opline.result_type = IS_VAR;
762            opline.result.var = get_temporary_variable(CG(active_op_array));
763            opline.op1_type = IS_CONST;
764            LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0);
765            CALCULATE_LITERAL_HASH(opline.op1.constant);
766            GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
767            if (class_node.op_type == IS_CONST) {
768                opline.op2_type = IS_CONST;
769                opline.op2.constant =
770                    zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
771            } else {
772                SET_NODE(opline.op2, &class_node);
773            }
774            opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
775            COPY_NODE(opline_ptr->op1, opline.result);
776
777            zend_llist_prepend_element(fetch_list_ptr, &opline);
778        } else {
779            if (opline_ptr->op1_type == IS_CONST) {
780                GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant);
781            }
782            if (class_node.op_type == IS_CONST) {
783                opline_ptr->op2_type = IS_CONST;
784                opline_ptr->op2.constant =
785                    zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
786            } else {
787                SET_NODE(opline_ptr->op2, &class_node);
788            }
789            opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER;
790        }
791    }
792}
793/* }}} */
794
795void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC) /* {{{ */
796{
797    fetch_simple_variable(result, varname, 1 TSRMLS_CC);
798
799    fetch_array_dim(result, result, first_dim TSRMLS_CC);
800}
801/* }}} */
802
803void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS_DC) /* {{{ */
804{
805    zend_op opline;
806    zend_llist *fetch_list_ptr;
807
808    zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
809
810    if (zend_is_function_or_method_call(parent)) {
811        init_op(&opline TSRMLS_CC);
812        opline.opcode = ZEND_SEPARATE;
813        SET_NODE(opline.op1, parent);
814        SET_UNUSED(opline.op2);
815        opline.result_type = IS_VAR;
816        opline.result.var = opline.op1.var;
817        zend_llist_add_element(fetch_list_ptr, &opline);
818    }
819
820    init_op(&opline TSRMLS_CC);
821    opline.opcode = ZEND_FETCH_DIM_W;   /* the backpatching routine assumes W */
822    opline.result_type = IS_VAR;
823    opline.result.var = get_temporary_variable(CG(active_op_array));
824    SET_NODE(opline.op1, parent);
825    SET_NODE(opline.op2, dim);
826    if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) {
827        ulong index;
828        int numeric = 0;
829
830        ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1);
831        if (numeric) {
832            zval_dtor(&CONSTANT(opline.op2.constant));
833            ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
834        } else {
835            CALCULATE_LITERAL_HASH(opline.op2.constant);
836        }
837    }
838
839    GET_NODE(result, opline.result);
840
841    zend_llist_add_element(fetch_list_ptr, &opline);
842}
843/* }}} */
844
845void fetch_string_offset(znode *result, const znode *parent, const znode *offset TSRMLS_DC) /* {{{ */
846{
847    fetch_array_dim(result, parent, offset TSRMLS_CC);
848}
849/* }}} */
850
851void zend_do_print(znode *result, const znode *arg TSRMLS_DC) /* {{{ */
852{
853    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
854
855    opline->result_type = IS_TMP_VAR;
856    opline->result.var = get_temporary_variable(CG(active_op_array));
857    opline->opcode = ZEND_PRINT;
858    SET_NODE(opline->op1, arg);
859    SET_UNUSED(opline->op2);
860    GET_NODE(result, opline->result);
861}
862/* }}} */
863
864void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */
865{
866    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
867
868    opline->opcode = ZEND_ECHO;
869    SET_NODE(opline->op1, arg);
870    SET_UNUSED(opline->op2);
871}
872/* }}} */
873
874void zend_do_abstract_method(const znode *function_name, znode *modifiers, const znode *body TSRMLS_DC) /* {{{ */
875{
876    char *method_type;
877
878    if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
879        Z_LVAL(modifiers->u.constant) |= ZEND_ACC_ABSTRACT;
880        method_type = "Interface";
881    } else {
882        method_type = "Abstract";
883    }
884
885    if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
886        if(modifiers->u.constant.value.lval & ZEND_ACC_PRIVATE) {
887            zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
888        }
889        if (Z_LVAL(body->u.constant) == ZEND_ACC_ABSTRACT) {
890            zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
891
892            opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
893            SET_UNUSED(opline->op1);
894            SET_UNUSED(opline->op2);
895        } else {
896            /* we had code in the function body */
897            zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
898        }
899    } else {
900        if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
901            zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
902        }
903    }
904}
905/* }}} */
906
907static zend_bool opline_is_fetch_this(const zend_op *opline TSRMLS_DC) /* {{{ */
908{
909    if ((opline->opcode == ZEND_FETCH_W) && (opline->op1_type == IS_CONST)
910        && (Z_TYPE(CONSTANT(opline->op1.constant)) == IS_STRING)
911        && ((opline->extended_value & ZEND_FETCH_STATIC_MEMBER) != ZEND_FETCH_STATIC_MEMBER)
912        && (Z_HASH_P(&CONSTANT(opline->op1.constant)) == THIS_HASHVAL)
913        && (Z_STRLEN(CONSTANT(opline->op1.constant)) == (sizeof("this")-1))
914        && !memcmp(Z_STRVAL(CONSTANT(opline->op1.constant)), "this", sizeof("this"))) {
915        return 1;
916    } else {
917        return 0;
918    }
919}
920/* }}} */
921
922void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */
923{
924    int last_op_number;
925    zend_op *opline;
926
927    if (value->op_type == IS_CV) {
928        zend_llist *fetch_list_ptr;
929
930        zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
931        if (fetch_list_ptr && fetch_list_ptr->head) {
932            opline = (zend_op *)fetch_list_ptr->head->data;
933
934            if (opline->opcode == ZEND_FETCH_DIM_W &&
935                opline->op1_type == IS_CV &&
936                opline->op1.var == value->u.op.var) {
937
938                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
939                opline->opcode = ZEND_FETCH_R;
940                opline->result_type = IS_VAR;
941                opline->result.var = get_temporary_variable(CG(active_op_array));
942                opline->op1_type = IS_CONST;
943                LITERAL_STRINGL(opline->op1,
944                    CG(active_op_array)->vars[value->u.op.var].name,
945                    CG(active_op_array)->vars[value->u.op.var].name_len, 1);
946                CALCULATE_LITERAL_HASH(opline->op1.constant);
947                SET_UNUSED(opline->op2);
948                opline->extended_value = ZEND_FETCH_LOCAL;
949                GET_NODE(value, opline->result);
950            }
951        }
952    }
953
954    zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC);
955
956    last_op_number = get_next_op_number(CG(active_op_array));
957    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
958
959    if (variable->op_type == IS_CV) {
960        if (variable->u.op.var == CG(active_op_array)->this_var) {
961            zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
962        }
963    } else if (variable->op_type == IS_VAR) {
964        int n = 0;
965
966        while (last_op_number - n > 0) {
967            zend_op *last_op;
968
969            last_op = &CG(active_op_array)->opcodes[last_op_number-n-1];
970
971            if (last_op->result_type == IS_VAR &&
972                last_op->result.var == variable->u.op.var) {
973                if (last_op->opcode == ZEND_FETCH_OBJ_W) {
974                    if (n > 0) {
975                        int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
976                        *opline = *last_op;
977                        MAKE_NOP(last_op);
978                        /* last_op = opline; */
979                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
980                        /* get_next_op can realloc, we need to move last_op */
981                        last_op = &CG(active_op_array)->opcodes[opline_no];
982                    }
983                    last_op->opcode = ZEND_ASSIGN_OBJ;
984                    zend_do_op_data(opline, value TSRMLS_CC);
985                    SET_UNUSED(opline->result);
986                    GET_NODE(result, last_op->result);
987                    return;
988                } else if (last_op->opcode == ZEND_FETCH_DIM_W) {
989                    if (n > 0) {
990                        int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
991                        *opline = *last_op;
992                        MAKE_NOP(last_op);
993                        /* last_op = opline; */
994                        /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */
995                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
996                        /* get_next_op can realloc, we need to move last_op */
997                        last_op = &CG(active_op_array)->opcodes[opline_no];
998                    }
999                    last_op->opcode = ZEND_ASSIGN_DIM;
1000                    zend_do_op_data(opline, value TSRMLS_CC);
1001                    opline->op2.var = get_temporary_variable(CG(active_op_array));
1002                    opline->op2_type = IS_VAR;
1003                    SET_UNUSED(opline->result);
1004                    GET_NODE(result, last_op->result);
1005                    return;
1006                } else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
1007                    zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1008                } else {
1009                    break;
1010                }
1011            }
1012            n++;
1013        }
1014    }
1015
1016    opline->opcode = ZEND_ASSIGN;
1017    SET_NODE(opline->op1, variable);
1018    SET_NODE(opline->op2, value);
1019    opline->result_type = IS_VAR;
1020    opline->result.var = get_temporary_variable(CG(active_op_array));
1021    GET_NODE(result, opline->result);
1022}
1023/* }}} */
1024
1025void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
1026{
1027    zend_op *opline;
1028
1029    if (lvar->op_type == IS_CV) {
1030        if (lvar->u.op.var == CG(active_op_array)->this_var) {
1031            zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1032        }
1033    } else if (lvar->op_type == IS_VAR) {
1034        int last_op_number = get_next_op_number(CG(active_op_array));
1035
1036        if (last_op_number > 0) {
1037            opline = &CG(active_op_array)->opcodes[last_op_number-1];
1038            if (opline_is_fetch_this(opline TSRMLS_CC)) {
1039                zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1040            }
1041        }
1042    }
1043
1044    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1045    opline->opcode = ZEND_ASSIGN_REF;
1046    if (zend_is_function_or_method_call(rvar)) {
1047        opline->extended_value = ZEND_RETURNS_FUNCTION;
1048    } else if (rvar->EA & ZEND_PARSED_NEW) {
1049        opline->extended_value = ZEND_RETURNS_NEW;
1050    } else {
1051        opline->extended_value = 0;
1052    }
1053    if (result) {
1054        opline->result_type = IS_VAR;
1055        opline->result.var = get_temporary_variable(CG(active_op_array));
1056        GET_NODE(result, opline->result);
1057    } else {
1058        opline->result_type = IS_UNUSED | EXT_TYPE_UNUSED;
1059    }
1060    SET_NODE(opline->op1, lvar);
1061    SET_NODE(opline->op2, rvar);
1062}
1063/* }}} */
1064
1065static inline void do_begin_loop(TSRMLS_D) /* {{{ */
1066{
1067    zend_brk_cont_element *brk_cont_element;
1068    int parent;
1069
1070    parent = CG(context).current_brk_cont;
1071    CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont;
1072    brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
1073    brk_cont_element->start = get_next_op_number(CG(active_op_array));
1074    brk_cont_element->parent = parent;
1075}
1076/* }}} */
1077
1078static inline void do_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */
1079{
1080    if (!has_loop_var) {
1081        /* The start fileld is used to free temporary variables in case of exceptions.
1082         * We won't try to free something of we don't have loop variable.
1083         */
1084        CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1;
1085    }
1086    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr;
1087    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array));
1088    CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent;
1089}
1090/* }}} */
1091
1092void zend_do_while_cond(const znode *expr, znode *close_bracket_token TSRMLS_DC) /* {{{ */
1093{
1094    int while_cond_op_number = get_next_op_number(CG(active_op_array));
1095    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1096
1097    opline->opcode = ZEND_JMPZ;
1098    SET_NODE(opline->op1, expr);
1099    close_bracket_token->u.op.opline_num = while_cond_op_number;
1100    SET_UNUSED(opline->op2);
1101
1102    do_begin_loop(TSRMLS_C);
1103    INC_BPC(CG(active_op_array));
1104}
1105/* }}} */
1106
1107void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC) /* {{{ */
1108{
1109    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1110
1111    /* add unconditional jump */
1112    opline->opcode = ZEND_JMP;
1113    opline->op1.opline_num = while_token->u.op.opline_num;
1114    SET_UNUSED(opline->op1);
1115    SET_UNUSED(opline->op2);
1116
1117    /* update while's conditional jmp */
1118    CG(active_op_array)->opcodes[close_bracket_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1119
1120    do_end_loop(while_token->u.op.opline_num, 0 TSRMLS_CC);
1121
1122    DEC_BPC(CG(active_op_array));
1123}
1124/* }}} */
1125
1126void zend_do_for_cond(const znode *expr, znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1127{
1128    int for_cond_op_number = get_next_op_number(CG(active_op_array));
1129    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1130
1131    opline->opcode = ZEND_JMPZNZ;
1132    SET_NODE(opline->op1, expr);  /* the conditional expression */
1133    second_semicolon_token->u.op.opline_num = for_cond_op_number;
1134    SET_UNUSED(opline->op2);
1135}
1136/* }}} */
1137
1138void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1139{
1140    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1141
1142    opline->opcode = ZEND_JMP;
1143    opline->op1.opline_num = cond_start->u.op.opline_num;
1144    CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
1145    SET_UNUSED(opline->op1);
1146    SET_UNUSED(opline->op2);
1147
1148    do_begin_loop(TSRMLS_C);
1149
1150    INC_BPC(CG(active_op_array));
1151}
1152/* }}} */
1153
1154void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1155{
1156    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1157
1158    opline->opcode = ZEND_JMP;
1159    opline->op1.opline_num = second_semicolon_token->u.op.opline_num+1;
1160    CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1161    SET_UNUSED(opline->op1);
1162    SET_UNUSED(opline->op2);
1163
1164    do_end_loop(second_semicolon_token->u.op.opline_num+1, 0 TSRMLS_CC);
1165
1166    DEC_BPC(CG(active_op_array));
1167}
1168/* }}} */
1169
1170void zend_do_pre_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1171{
1172    int last_op_number = get_next_op_number(CG(active_op_array));
1173    zend_op *opline;
1174
1175    if (last_op_number > 0) {
1176        zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1177
1178        if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1179            last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ;
1180            last_op->result_type = IS_VAR;
1181            last_op->result.var = get_temporary_variable(CG(active_op_array));
1182            GET_NODE(result, last_op->result);
1183            return;
1184        }
1185    }
1186
1187    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1188    opline->opcode = op;
1189    SET_NODE(opline->op1, op1);
1190    SET_UNUSED(opline->op2);
1191    opline->result_type = IS_VAR;
1192    opline->result.var = get_temporary_variable(CG(active_op_array));
1193    GET_NODE(result, opline->result);
1194}
1195/* }}} */
1196
1197void zend_do_post_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1198{
1199    int last_op_number = get_next_op_number(CG(active_op_array));
1200    zend_op *opline;
1201
1202    if (last_op_number > 0) {
1203        zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1204
1205        if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1206            last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ;
1207            last_op->result_type = IS_TMP_VAR;
1208            last_op->result.var = get_temporary_variable(CG(active_op_array));
1209            GET_NODE(result, last_op->result);
1210            return;
1211        }
1212    }
1213
1214    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1215    opline->opcode = op;
1216    SET_NODE(opline->op1, op1);
1217    SET_UNUSED(opline->op2);
1218    opline->result_type = IS_TMP_VAR;
1219    opline->result.var = get_temporary_variable(CG(active_op_array));
1220    GET_NODE(result, opline->result);
1221}
1222/* }}} */
1223
1224void zend_do_if_cond(const znode *cond, znode *closing_bracket_token TSRMLS_DC) /* {{{ */
1225{
1226    int if_cond_op_number = get_next_op_number(CG(active_op_array));
1227    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1228
1229    opline->opcode = ZEND_JMPZ;
1230    SET_NODE(opline->op1, cond);
1231    closing_bracket_token->u.op.opline_num = if_cond_op_number;
1232    SET_UNUSED(opline->op2);
1233    INC_BPC(CG(active_op_array));
1234}
1235/* }}} */
1236
1237void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC) /* {{{ */
1238{
1239    int if_end_op_number = get_next_op_number(CG(active_op_array));
1240    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1241    zend_llist *jmp_list_ptr;
1242
1243    opline->opcode = ZEND_JMP;
1244    /* save for backpatching */
1245    if (initialize) {
1246        zend_llist jmp_list;
1247
1248        zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
1249        zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
1250    }
1251    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1252    zend_llist_add_element(jmp_list_ptr, &if_end_op_number);
1253
1254    CG(active_op_array)->opcodes[closing_bracket_token->u.op.opline_num].op2.opline_num = if_end_op_number+1;
1255    SET_UNUSED(opline->op1);
1256    SET_UNUSED(opline->op2);
1257}
1258/* }}} */
1259
1260void zend_do_if_end(TSRMLS_D) /* {{{ */
1261{
1262    int next_op_number = get_next_op_number(CG(active_op_array));
1263    zend_llist *jmp_list_ptr;
1264    zend_llist_element *le;
1265
1266    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1267    for (le=jmp_list_ptr->head; le; le = le->next) {
1268        CG(active_op_array)->opcodes[*((int *) le->data)].op1.opline_num = next_op_number;
1269    }
1270    zend_llist_destroy(jmp_list_ptr);
1271    zend_stack_del_top(&CG(bp_stack));
1272    DEC_BPC(CG(active_op_array));
1273}
1274/* }}} */
1275
1276void zend_check_writable_variable(const znode *variable) /* {{{ */
1277{
1278    zend_uint type = variable->EA;
1279
1280    if (type & ZEND_PARSED_METHOD_CALL) {
1281        zend_error(E_COMPILE_ERROR, "Can't use method return value in write context");
1282    }
1283    if (type == ZEND_PARSED_FUNCTION_CALL) {
1284        zend_error(E_COMPILE_ERROR, "Can't use function return value in write context");
1285    }
1286}
1287/* }}} */
1288
1289void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */
1290{
1291    zend_llist fetch_list;
1292
1293    zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0);
1294    zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist));
1295}
1296/* }}} */
1297
1298void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */
1299{
1300    zend_llist *fetch_list_ptr;
1301    zend_llist_element *le;
1302    zend_op *opline = NULL;
1303    zend_op *opline_ptr;
1304    zend_uint this_var = -1;
1305
1306    zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
1307
1308    le = fetch_list_ptr->head;
1309
1310    /* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */
1311
1312    if (le) {
1313        opline_ptr = (zend_op *)le->data;
1314        if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
1315            /* convert to FETCH_?(this) into IS_CV */
1316            if (CG(active_op_array)->last == 0 ||
1317                CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) {
1318
1319                this_var = opline_ptr->result.var;
1320                if (CG(active_op_array)->this_var == -1) {
1321                    CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(CONSTANT(opline_ptr->op1.constant)), Z_STRLEN(CONSTANT(opline_ptr->op1.constant)), Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC);
1322                    Z_TYPE(CONSTANT(opline_ptr->op1.constant)) = IS_NULL;
1323                } else {
1324                    zend_del_literal(CG(active_op_array), opline_ptr->op1.constant);
1325                }
1326                le = le->next;
1327                if (variable->op_type == IS_VAR &&
1328                    variable->u.op.var == this_var) {
1329                    variable->op_type = IS_CV;
1330                    variable->u.op.var = CG(active_op_array)->this_var;
1331                }
1332            } else if (CG(active_op_array)->this_var == -1) {
1333                CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1, THIS_HASHVAL TSRMLS_CC);
1334            }
1335        }
1336
1337        while (le) {
1338            opline_ptr = (zend_op *)le->data;
1339            if (opline_ptr->opcode == ZEND_SEPARATE) {
1340                if (type != BP_VAR_R && type != BP_VAR_IS) {
1341                    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1342                    memcpy(opline, opline_ptr, sizeof(zend_op));
1343                }
1344                le = le->next;
1345                continue;
1346            }
1347            opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1348            memcpy(opline, opline_ptr, sizeof(zend_op));
1349            if (opline->op1_type == IS_VAR &&
1350                opline->op1.var == this_var) {
1351                opline->op1_type = IS_CV;
1352                opline->op1.var = CG(active_op_array)->this_var;
1353            }
1354            switch (type) {
1355                case BP_VAR_R:
1356                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1357                        zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1358                    }
1359                    opline->opcode -= 3;
1360                    break;
1361                case BP_VAR_W:
1362                    break;
1363                case BP_VAR_RW:
1364                    opline->opcode += 3;
1365                    break;
1366                case BP_VAR_IS:
1367                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1368                        zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1369                    }
1370                    opline->opcode += 6; /* 3+3 */
1371                    break;
1372                case BP_VAR_FUNC_ARG:
1373                    opline->opcode += 9; /* 3+3+3 */
1374                    opline->extended_value |= arg_offset;
1375                    break;
1376                case BP_VAR_UNSET:
1377                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1378                        zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting");
1379                    }
1380                    opline->opcode += 12; /* 3+3+3+3 */
1381                    break;
1382            }
1383            le = le->next;
1384        }
1385        if (opline && type == BP_VAR_W && arg_offset) {
1386            opline->extended_value |= ZEND_FETCH_MAKE_REF;
1387        }
1388    }
1389    zend_llist_destroy(fetch_list_ptr);
1390    zend_stack_del_top(&CG(bp_stack));
1391}
1392/* }}} */
1393
1394void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
1395{
1396    zend_op *opline;
1397
1398    if (Z_STRLEN(op2->u.constant) > 1) {
1399        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1400        opline->opcode = ZEND_ADD_STRING;
1401    } else if (Z_STRLEN(op2->u.constant) == 1) {
1402        int ch = *Z_STRVAL(op2->u.constant);
1403
1404        /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */
1405        efree(Z_STRVAL(op2->u.constant));
1406        ZVAL_LONG(&op2->u.constant, ch);
1407        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1408        opline->opcode = ZEND_ADD_CHAR;
1409    } else { /* String can be empty after a variable at the end of a heredoc */
1410        efree(Z_STRVAL(op2->u.constant));
1411        return;
1412    }
1413
1414    if (op1) {
1415        SET_NODE(opline->op1, op1);
1416        SET_NODE(opline->result, op1);
1417    } else {
1418        SET_UNUSED(opline->op1);
1419        opline->result_type = IS_TMP_VAR;
1420        opline->result.var = get_temporary_variable(CG(active_op_array));
1421    }
1422    SET_NODE(opline->op2, op2);
1423    GET_NODE(result, opline->result);
1424}
1425/* }}} */
1426
1427void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
1428{
1429    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1430
1431    opline->opcode = ZEND_ADD_VAR;
1432
1433    if (op1) {
1434        SET_NODE(opline->op1, op1);
1435        SET_NODE(opline->result, op1);
1436    } else {
1437        SET_UNUSED(opline->op1);
1438        opline->result_type = IS_TMP_VAR;
1439        opline->result.var = get_temporary_variable(CG(active_op_array));
1440    }
1441    SET_NODE(opline->op2, op2);
1442    GET_NODE(result, opline->result);
1443}
1444/* }}} */
1445
1446void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
1447{
1448    if (op1->op_type==IS_TMP_VAR) {
1449        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1450
1451        opline->opcode = ZEND_FREE;
1452        SET_NODE(opline->op1, op1);
1453        SET_UNUSED(opline->op2);
1454    } else if (op1->op_type==IS_VAR) {
1455        zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
1456
1457        while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) {
1458            opline--;
1459        }
1460        if (opline->result_type == IS_VAR
1461            && opline->result.var == op1->u.op.var) {
1462            if (opline->opcode == ZEND_FETCH_R ||
1463                opline->opcode == ZEND_FETCH_DIM_R ||
1464                opline->opcode == ZEND_FETCH_OBJ_R ||
1465                opline->opcode == ZEND_QM_ASSIGN_VAR) {
1466                /* It's very rare and useless case. It's better to use
1467                   additional FREE opcode and simplify the FETCH handlers
1468                   their selves */
1469                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1470                opline->opcode = ZEND_FREE;
1471                SET_NODE(opline->op1, op1);
1472                SET_UNUSED(opline->op2);
1473            } else {
1474                opline->result_type |= EXT_TYPE_UNUSED;
1475            }
1476        } else {
1477            while (opline>CG(active_op_array)->opcodes) {
1478                if (opline->opcode == ZEND_FETCH_DIM_R
1479                    && opline->op1_type == IS_VAR
1480                    && opline->op1.var == op1->u.op.var) {
1481                    /* This should the end of a list() construct
1482                     * Mark its result as unused
1483                     */
1484                    opline->extended_value = ZEND_FETCH_STANDARD;
1485                    break;
1486                } else if (opline->result_type==IS_VAR
1487                    && opline->result.var == op1->u.op.var) {
1488                    if (opline->opcode == ZEND_NEW) {
1489                        opline->result_type |= EXT_TYPE_UNUSED;
1490                    }
1491                    break;
1492                }
1493                opline--;
1494            }
1495        }
1496    } else if (op1->op_type == IS_CONST) {
1497        zval_dtor(&op1->u.constant);
1498    }
1499}
1500/* }}} */
1501
1502int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier) /* {{{ */
1503{
1504    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_PPP_MASK)
1505        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_PPP_MASK)) {
1506        zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
1507    }
1508    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_ABSTRACT)
1509        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_ABSTRACT)) {
1510        zend_error(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
1511    }
1512    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_STATIC)
1513        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_STATIC)) {
1514        zend_error(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
1515    }
1516    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_FINAL)
1517        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_FINAL)) {
1518        zend_error(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
1519    }
1520    if (((Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant)) & (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) == (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) {
1521        zend_error(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
1522    }
1523    return (Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant));
1524}
1525/* }}} */
1526
1527void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
1528{
1529    zend_op_array op_array;
1530    char *name = function_name->u.constant.value.str.val;
1531    int name_len = function_name->u.constant.value.str.len;
1532    int function_begin_line = function_token->u.op.opline_num;
1533    zend_uint fn_flags;
1534    const char *lcname;
1535    zend_bool orig_interactive;
1536    ALLOCA_FLAG(use_heap)
1537
1538    if (is_method) {
1539        if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1540            if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) {
1541                zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
1542            }
1543            Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
1544        }
1545        fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
1546    } else {
1547        fn_flags = 0;
1548    }
1549    if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
1550        zend_error(E_STRICT, "Static function %s%s%s() should not be abstract", is_method ? CG(active_class_entry)->name : "", is_method ? "::" : "", Z_STRVAL(function_name->u.constant));
1551    }
1552
1553    function_token->u.op_array = CG(active_op_array);
1554
1555    orig_interactive = CG(interactive);
1556    CG(interactive) = 0;
1557    init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
1558    CG(interactive) = orig_interactive;
1559
1560    op_array.function_name = name;
1561    if (return_reference) {
1562        op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1563    }
1564    op_array.fn_flags |= fn_flags;
1565
1566    op_array.scope = is_method?CG(active_class_entry):NULL;
1567    op_array.prototype = NULL;
1568
1569    op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);
1570
1571    if (is_method) {
1572        int result;
1573
1574        lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);
1575
1576        if (IS_INTERNED(lcname)) {
1577            result = zend_hash_quick_add(&CG(active_class_entry)->function_table, lcname, name_len+1, INTERNED_HASH(lcname), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1578        } else {
1579            result = zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1580        }
1581        if (result == FAILURE) {
1582            zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
1583        }
1584
1585        zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1586        zend_init_compiler_context(TSRMLS_C);
1587
1588        if (fn_flags & ZEND_ACC_ABSTRACT) {
1589            CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1590        }
1591
1592        if (!(fn_flags & ZEND_ACC_PPP_MASK)) {
1593            fn_flags |= ZEND_ACC_PUBLIC;
1594        }
1595
1596        if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1597            if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1598                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1599                    zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1600                }
1601            } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1602                if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1603                    zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1604                }
1605            } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1606                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1607                    zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1608                }
1609            } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1610                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1611                    zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1612                }
1613            } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1614                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1615                    zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1616                }
1617            } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1618                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1619                    zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1620                }
1621            } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1622                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1623                    zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1624                }
1625            } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1626                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1627                    zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1628                }
1629            }
1630        } else {
1631            char *class_lcname;
1632
1633            class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
1634            zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
1635            /* Improve after RC: cache the lowercase class name */
1636
1637            if ((CG(active_class_entry)->name_length == name_len) && ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) && (!memcmp(class_lcname, lcname, name_len))) {
1638                if (!CG(active_class_entry)->constructor) {
1639                    CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1640                }
1641            } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) {
1642                if (CG(active_class_entry)->constructor) {
1643                    zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name);
1644                }
1645                CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1646            } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) {
1647                CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array);
1648            } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) {
1649                CG(active_class_entry)->clone = (zend_function *) CG(active_op_array);
1650            } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1651                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1652                    zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1653                }
1654                CG(active_class_entry)->__call = (zend_function *) CG(active_op_array);
1655            } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1656                if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1657                    zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1658                }
1659                CG(active_class_entry)->__callstatic = (zend_function *) CG(active_op_array);
1660            } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1661                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1662                    zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1663                }
1664                CG(active_class_entry)->__get = (zend_function *) CG(active_op_array);
1665            } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1666                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1667                    zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1668                }
1669                CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
1670            } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1671                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1672                    zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1673                }
1674                CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array);
1675            } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1676                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1677                    zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1678                }
1679                CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
1680            } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1681                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1682                    zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1683                }
1684                CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
1685            } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1686                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1687                    zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1688                }
1689            } else if (!(fn_flags & ZEND_ACC_STATIC)) {
1690                CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
1691            }
1692            free_alloca(class_lcname, use_heap);
1693        }
1694
1695        str_efree(lcname);
1696    } else {
1697        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1698        zval key;
1699
1700        if (CG(current_namespace)) {
1701            /* Prefix function name with current namespace name */
1702            znode tmp;
1703
1704            tmp.u.constant = *CG(current_namespace);
1705            zval_copy_ctor(&tmp.u.constant);
1706            zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
1707            op_array.function_name = Z_STRVAL(tmp.u.constant);
1708            name_len = Z_STRLEN(tmp.u.constant);
1709            lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
1710        } else {
1711            lcname = zend_str_tolower_dup(name, name_len);
1712        }
1713
1714        opline->opcode = ZEND_DECLARE_FUNCTION;
1715        opline->op1_type = IS_CONST;
1716        build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC);
1717        opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
1718        Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
1719        opline->op2_type = IS_CONST;
1720        LITERAL_STRINGL(opline->op2, lcname, name_len, 0);
1721        CALCULATE_LITERAL_HASH(opline->op2.constant);
1722        opline->extended_value = ZEND_DECLARE_FUNCTION;
1723        zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1724        zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1725        zend_init_compiler_context(TSRMLS_C);
1726    }
1727
1728    if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
1729        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1730
1731        opline->opcode = ZEND_EXT_NOP;
1732        opline->lineno = function_begin_line;
1733        SET_UNUSED(opline->op1);
1734        SET_UNUSED(opline->op2);
1735    }
1736
1737    {
1738        /* Push a separator to the switch stack */
1739        zend_switch_entry switch_entry;
1740
1741        switch_entry.cond.op_type = IS_UNUSED;
1742        switch_entry.default_case = 0;
1743        switch_entry.control_var = 0;
1744
1745        zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
1746    }
1747
1748    {
1749        /* Push a separator to the foreach stack */
1750        zend_op dummy_opline;
1751
1752        dummy_opline.result_type = IS_UNUSED;
1753
1754        zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
1755    }
1756
1757    if (CG(doc_comment)) {
1758        CG(active_op_array)->doc_comment = CG(doc_comment);
1759        CG(active_op_array)->doc_comment_len = CG(doc_comment_len);
1760        CG(doc_comment) = NULL;
1761        CG(doc_comment_len) = 0;
1762    }
1763}
1764/* }}} */
1765
1766void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC) /* {{{ */
1767{
1768    znode          function_name;
1769    zend_op_array *current_op_array = CG(active_op_array);
1770    int            current_op_number = get_next_op_number(CG(active_op_array));
1771    zend_op       *current_op;
1772
1773    function_name.op_type = IS_CONST;
1774    ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1);
1775
1776    zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC);
1777
1778    result->op_type = IS_TMP_VAR;
1779    result->u.op.var = get_temporary_variable(current_op_array);
1780
1781    current_op = &current_op_array->opcodes[current_op_number];
1782    current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION;
1783    zend_del_literal(current_op_array, current_op->op2.constant);
1784    SET_UNUSED(current_op->op2);
1785    SET_NODE(current_op->result, result);
1786    if (is_static) {
1787        CG(active_op_array)->fn_flags |= ZEND_ACC_STATIC;
1788    }
1789    CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE;
1790}
1791/* }}} */
1792
1793void zend_do_handle_exception(TSRMLS_D) /* {{{ */
1794{
1795    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1796
1797    opline->opcode = ZEND_HANDLE_EXCEPTION;
1798    SET_UNUSED(opline->op1);
1799    SET_UNUSED(opline->op2);
1800}
1801/* }}} */
1802
1803void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /* {{{ */
1804{
1805    char lcname[16];
1806    int name_len;
1807
1808    zend_do_extended_info(TSRMLS_C);
1809    zend_do_return(NULL, 0 TSRMLS_CC);
1810
1811    pass_two(CG(active_op_array) TSRMLS_CC);
1812    zend_release_labels(0 TSRMLS_CC);
1813
1814    if (CG(active_class_entry)) {
1815        zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
1816    } else {
1817        /* we don't care if the function name is longer, in fact lowercasing only
1818         * the beginning of the name speeds up the check process */
1819        name_len = strlen(CG(active_op_array)->function_name);
1820        zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1));
1821        lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
1822        if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) {
1823            zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME);
1824        }
1825    }
1826
1827    CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
1828    CG(active_op_array) = function_token->u.op_array;
1829
1830
1831    /* Pop the switch and foreach separators */
1832    zend_stack_del_top(&CG(switch_cond_stack));
1833    zend_stack_del_top(&CG(foreach_copy_stack));
1834}
1835/* }}} */
1836
1837void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
1838{
1839    zend_op *opline;
1840    zend_arg_info *cur_arg_info;
1841    znode var;
1842
1843    if (class_type->op_type == IS_CONST &&
1844        Z_TYPE(class_type->u.constant) == IS_STRING &&
1845        Z_STRLEN(class_type->u.constant) == 0) {
1846        /* Usage of namespace as class name not in namespace */
1847        zval_dtor(&class_type->u.constant);
1848        zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
1849        return;
1850    }
1851
1852    if (zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0 TSRMLS_CC)) {
1853        zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
1854    } else {
1855        var.op_type = IS_CV;
1856        var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, 0 TSRMLS_CC);
1857        Z_STRVAL(varname->u.constant) = (char*)CG(active_op_array)->vars[var.u.op.var].name;
1858        var.EA = 0;
1859        if (CG(active_op_array)->vars[var.u.op.var].hash_value == THIS_HASHVAL &&
1860            Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
1861            !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
1862            if (CG(active_op_array)->scope &&
1863                (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
1864                zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1865            }
1866            CG(active_op_array)->this_var = var.u.op.var;
1867        }
1868    }
1869
1870    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1871    CG(active_op_array)->num_args++;
1872    opline->opcode = op;
1873    SET_NODE(opline->result, &var);
1874    SET_NODE(opline->op1, offset);
1875    if (op == ZEND_RECV_INIT) {
1876        SET_NODE(opline->op2, initialization);
1877    } else {
1878        CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
1879        SET_UNUSED(opline->op2);
1880    }
1881    CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
1882    cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
1883    cur_arg_info->name = zend_new_interned_string(estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len), varname->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1884    cur_arg_info->name_len = varname->u.constant.value.str.len;
1885    cur_arg_info->type_hint = 0;
1886    cur_arg_info->allow_null = 1;
1887    cur_arg_info->pass_by_reference = pass_by_reference;
1888    cur_arg_info->class_name = NULL;
1889    cur_arg_info->class_name_len = 0;
1890
1891    if (class_type->op_type != IS_UNUSED) {
1892        cur_arg_info->allow_null = 0;
1893
1894        if (class_type->u.constant.type != IS_NULL) {
1895            if (class_type->u.constant.type == IS_ARRAY) {
1896                cur_arg_info->type_hint = IS_ARRAY;
1897                if (op == ZEND_RECV_INIT) {
1898                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1899                        cur_arg_info->allow_null = 1;
1900                    } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY && Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) {
1901                        zend_error(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL");
1902                    }
1903                }
1904            } else if (class_type->u.constant.type == IS_CALLABLE) {
1905                cur_arg_info->type_hint = IS_CALLABLE;
1906                if (op == ZEND_RECV_INIT) {
1907                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1908                        cur_arg_info->allow_null = 1;
1909                    } else {
1910                        zend_error(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
1911                    }
1912                }
1913            } else {
1914                cur_arg_info->type_hint = IS_OBJECT;
1915                if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) {
1916                    zend_resolve_class_name(class_type, opline->extended_value, 1 TSRMLS_CC);
1917                }
1918                Z_STRVAL(class_type->u.constant) = (char*)zend_new_interned_string(class_type->u.constant.value.str.val, class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1919                cur_arg_info->class_name = class_type->u.constant.value.str.val;
1920                cur_arg_info->class_name_len = class_type->u.constant.value.str.len;
1921                if (op == ZEND_RECV_INIT) {
1922                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1923                        cur_arg_info->allow_null = 1;
1924                    } else {
1925                        zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL");
1926                    }
1927                }
1928            }
1929        }
1930    }
1931}
1932/* }}} */
1933
1934int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
1935{
1936    zend_function *function;
1937    char *lcname;
1938    char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
1939
1940    zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC);
1941
1942    if (check_namespace && CG(current_namespace) && !is_compound) {
1943            /* We assume we call function from the current namespace
1944            if it is not prefixed. */
1945
1946            /* In run-time PHP will check for function with full name and
1947            internal function with short name */
1948            zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
1949            return 1;
1950    }
1951
1952    lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
1953    if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
1954        ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
1955        (function->type == ZEND_INTERNAL_FUNCTION))) {
1956            zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
1957            efree(lcname);
1958            return 1; /* Dynamic */
1959    }
1960    efree(function_name->u.constant.value.str.val);
1961    function_name->u.constant.value.str.val = lcname;
1962
1963    zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
1964    if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
1965        CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
1966    }
1967    zend_do_extended_fcall_begin(TSRMLS_C);
1968    return 0;
1969}
1970/* }}} */
1971
1972void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
1973{
1974    zend_op *last_op;
1975    int last_op_number;
1976    unsigned char *ptr = NULL;
1977
1978    zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC);
1979    zend_do_begin_variable_parse(TSRMLS_C);
1980
1981    last_op_number = get_next_op_number(CG(active_op_array))-1;
1982    last_op = &CG(active_op_array)->opcodes[last_op_number];
1983
1984    if ((last_op->op2_type == IS_CONST) && (Z_TYPE(CONSTANT(last_op->op2.constant)) == IS_STRING) && (Z_STRLEN(CONSTANT(last_op->op2.constant)) == sizeof(ZEND_CLONE_FUNC_NAME)-1)
1985        && !zend_binary_strcasecmp(Z_STRVAL(CONSTANT(last_op->op2.constant)), Z_STRLEN(CONSTANT(last_op->op2.constant)), ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) {
1986        zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead");
1987    }
1988
1989    if (last_op->opcode == ZEND_FETCH_OBJ_R) {
1990        if (last_op->op2_type == IS_CONST) {
1991            zval name;
1992            name = CONSTANT(last_op->op2.constant);
1993            if (Z_TYPE(name) != IS_STRING) {
1994                zend_error(E_COMPILE_ERROR, "Method name must be a string");
1995            }
1996            if (!IS_INTERNED(Z_STRVAL(name))) {
1997                Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
1998            }
1999            FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2000            last_op->op2.constant =
2001                zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC);
2002            GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2003        }
2004        last_op->opcode = ZEND_INIT_METHOD_CALL;
2005        last_op->result_type = IS_UNUSED;
2006        last_op->result.num = CG(context).nested_calls;
2007        Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
2008    } else {
2009        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2010        opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2011        opline->result.num = CG(context).nested_calls;
2012        SET_UNUSED(opline->op1);
2013        if (left_bracket->op_type == IS_CONST) {
2014            opline->op2_type = IS_CONST;
2015            opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC);
2016            GET_CACHE_SLOT(opline->op2.constant);
2017        } else {
2018            SET_NODE(opline->op2, left_bracket);
2019        }
2020    }
2021
2022    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2023    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2024        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2025    }
2026    zend_do_extended_fcall_begin(TSRMLS_C);
2027}
2028/* }}} */
2029
2030void zend_do_clone(znode *result, const znode *expr TSRMLS_DC) /* {{{ */
2031{
2032    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2033
2034    opline->opcode = ZEND_CLONE;
2035    SET_NODE(opline->op1, expr);
2036    SET_UNUSED(opline->op2);
2037    opline->result_type = IS_VAR;
2038    opline->result.var = get_temporary_variable(CG(active_op_array));
2039    GET_NODE(result, opline->result);
2040}
2041/* }}} */
2042
2043void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */
2044{
2045    unsigned char *ptr = NULL;
2046    zend_op *opline;
2047
2048    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2049    if (ns_call) {
2050        /* In run-time PHP will check for function with full name and
2051           internal function with short name */
2052        opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
2053        opline->result.num = CG(context).nested_calls;
2054        SET_UNUSED(opline->op1);
2055        opline->op2_type = IS_CONST;
2056        opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2057        GET_CACHE_SLOT(opline->op2.constant);
2058    } else {
2059        opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2060        opline->result.num = CG(context).nested_calls;
2061        SET_UNUSED(opline->op1);
2062        if (function_name->op_type == IS_CONST) {
2063            opline->op2_type = IS_CONST;
2064            opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2065            GET_CACHE_SLOT(opline->op2.constant);
2066        } else {
2067            SET_NODE(opline->op2, function_name);
2068        }
2069    }
2070
2071    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2072    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2073        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2074    }
2075    zend_do_extended_fcall_begin(TSRMLS_C);
2076}
2077/* }}} */
2078
2079void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
2080{
2081    znode tmp;
2082    int len;
2083    zval **ns;
2084    char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant));
2085
2086    if (Z_STRVAL(element_name->u.constant)[0] == '\\') {
2087        /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */
2088        memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant));
2089        --Z_STRLEN(element_name->u.constant);
2090        return;
2091    }
2092
2093    if(!check_namespace) {
2094        return;
2095    }
2096
2097    if (compound && CG(current_import)) {
2098        len = compound - Z_STRVAL(element_name->u.constant);
2099        lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len);
2100        /* Check if first part of compound name is an import name */
2101        if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2102            /* Substitute import name */
2103            tmp.op_type = IS_CONST;
2104            tmp.u.constant = **ns;
2105            zval_copy_ctor(&tmp.u.constant);
2106            len += 1;
2107            Z_STRLEN(element_name->u.constant) -= len;
2108            memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1);
2109            zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC);
2110            *element_name = tmp;
2111            efree(lcname);
2112            return;
2113        }
2114        efree(lcname);
2115    }
2116
2117    if (CG(current_namespace)) {
2118        tmp = *element_name;
2119        Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace));
2120        Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1);
2121        memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
2122        memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1);
2123        memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1);
2124        STR_FREE(Z_STRVAL(element_name->u.constant));
2125        *element_name = tmp;
2126    }
2127}
2128/* }}} */
2129
2130void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */
2131{
2132    char *lcname;
2133    int lctype;
2134    znode constant_name;
2135
2136    lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len);
2137    lctype = zend_get_class_fetch_type(lcname, strlen(lcname));
2138    switch (lctype) {
2139        case ZEND_FETCH_CLASS_SELF:
2140            if (!CG(active_class_entry)) {
2141                zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active");
2142            }
2143            zval_dtor(&class_name->u.constant);
2144            class_name->op_type = IS_CONST;
2145            ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1);
2146            *result = *class_name;
2147            break;
2148        case ZEND_FETCH_CLASS_STATIC:
2149        case ZEND_FETCH_CLASS_PARENT:
2150            if (is_static) {
2151                zend_error(E_COMPILE_ERROR,
2152                    "%s::class cannot be used for compile-time class name resolution",
2153                    lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2154                    );
2155            }
2156            if (!CG(active_class_entry)) {
2157                zend_error(E_COMPILE_ERROR,
2158                    "Cannot access %s::class when no class scope is active",
2159                    lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2160                    );
2161            }
2162            constant_name.op_type = IS_CONST;
2163            ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
2164            zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
2165            break;
2166        case ZEND_FETCH_CLASS_DEFAULT:
2167            zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2168            *result = *class_name;
2169            break;
2170    }
2171
2172    efree(lcname);
2173
2174}
2175/* }}} */
2176
2177void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */
2178{
2179    char *compound;
2180    char *lcname;
2181    zval **ns;
2182    znode tmp;
2183    int len;
2184
2185    compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant));
2186    if (compound) {
2187        /* This is a compound class name that contains namespace prefix */
2188        if (Z_STRVAL(class_name->u.constant)[0] == '\\') {
2189            /* The STRING name has "\" prefix */
2190            Z_STRLEN(class_name->u.constant) -= 1;
2191            memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1);
2192            Z_STRVAL(class_name->u.constant) = erealloc(
2193            Z_STRVAL(class_name->u.constant),
2194            Z_STRLEN(class_name->u.constant) + 1);
2195
2196            if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2197                zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant));
2198            }
2199        } else {
2200            if (CG(current_import)) {
2201                len = compound - Z_STRVAL(class_name->u.constant);
2202                lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len);
2203                /* Check if first part of compound name is an import name */
2204                if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2205                    /* Substitute import name */
2206                    tmp.op_type = IS_CONST;
2207                    tmp.u.constant = **ns;
2208                    zval_copy_ctor(&tmp.u.constant);
2209                    len += 1;
2210                    Z_STRLEN(class_name->u.constant) -= len;
2211                    memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1);
2212                    zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2213                    *class_name = tmp;
2214                    efree(lcname);
2215                    return;
2216                }
2217                efree(lcname);
2218            }
2219            /* Here name is not prefixed with \ and not imported */
2220            if (CG(current_namespace)) {
2221                tmp.op_type = IS_CONST;
2222                tmp.u.constant = *CG(current_namespace);
2223                zval_copy_ctor(&tmp.u.constant);
2224                zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2225                *class_name = tmp;
2226            }
2227        }
2228    } else if (CG(current_import) || CG(current_namespace)) {
2229        /* this is a plain name (without \) */
2230        lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
2231
2232        if (CG(current_import) &&
2233            zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns) == SUCCESS) {
2234            /* The given name is an import name. Substitute it. */
2235            zval_dtor(&class_name->u.constant);
2236            class_name->u.constant = **ns;
2237            zval_copy_ctor(&class_name->u.constant);
2238        } else if (CG(current_namespace)) {
2239            /* plain name, no import - prepend current namespace to it */
2240            tmp.op_type = IS_CONST;
2241            tmp.u.constant = *CG(current_namespace);
2242            zval_copy_ctor(&tmp.u.constant);
2243            zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2244            *class_name = tmp;
2245        }
2246        efree(lcname);
2247    }
2248}
2249/* }}} */
2250
2251void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
2252{
2253    long fetch_class_op_number;
2254    zend_op *opline;
2255
2256    if (class_name->op_type == IS_CONST &&
2257        Z_TYPE(class_name->u.constant) == IS_STRING &&
2258        Z_STRLEN(class_name->u.constant) == 0) {
2259        /* Usage of namespace as class name not in namespace */
2260        zval_dtor(&class_name->u.constant);
2261        zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
2262        return;
2263    }
2264
2265    fetch_class_op_number = get_next_op_number(CG(active_op_array));
2266    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2267
2268    opline->opcode = ZEND_FETCH_CLASS;
2269    SET_UNUSED(opline->op1);
2270    opline->extended_value = ZEND_FETCH_CLASS_GLOBAL;
2271    CG(catch_begin) = fetch_class_op_number;
2272    if (class_name->op_type == IS_CONST) {
2273        int fetch_type;
2274
2275        fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
2276        switch (fetch_type) {
2277            case ZEND_FETCH_CLASS_SELF:
2278            case ZEND_FETCH_CLASS_PARENT:
2279            case ZEND_FETCH_CLASS_STATIC:
2280                SET_UNUSED(opline->op2);
2281                opline->extended_value = fetch_type;
2282                zval_dtor(&class_name->u.constant);
2283                break;
2284            default:
2285                zend_resolve_class_name(class_name, opline->extended_value, 0 TSRMLS_CC);
2286                opline->op2_type = IS_CONST;
2287                opline->op2.constant =
2288                    zend_add_class_name_literal(CG(active_op_array), &class_name->u.constant TSRMLS_CC);
2289                break;
2290        }
2291    } else {
2292        SET_NODE(opline->op2, class_name);
2293    }
2294    opline->result.var = get_temporary_variable(CG(active_op_array));
2295    opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */
2296    GET_NODE(result, opline->result);
2297    result->EA = opline->extended_value;
2298}
2299/* }}} */
2300
2301void zend_do_label(znode *label TSRMLS_DC) /* {{{ */
2302{
2303    zend_label dest;
2304
2305    if (!CG(context).labels) {
2306        ALLOC_HASHTABLE(CG(context).labels);
2307        zend_hash_init(CG(context).labels, 4, NULL, NULL, 0);
2308    }
2309
2310    dest.brk_cont = CG(context).current_brk_cont;
2311    dest.opline_num = get_next_op_number(CG(active_op_array));
2312
2313    if (zend_hash_add(CG(context).labels, Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) {
2314        zend_error(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL(label->u.constant));
2315    }
2316
2317    /* Done with label now */
2318    zval_dtor(&label->u.constant);
2319}
2320/* }}} */
2321
2322void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */
2323{
2324    zend_label *dest;
2325    long current, distance;
2326    zval *label;
2327
2328    if (pass2) {
2329        label = opline->op2.zv;
2330    } else {
2331        label = &CONSTANT_EX(op_array, opline->op2.constant);
2332    }
2333    if (CG(context).labels == NULL ||
2334        zend_hash_find(CG(context).labels, Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) {
2335
2336        if (pass2) {
2337            CG(in_compilation) = 1;
2338            CG(active_op_array) = op_array;
2339            CG(zend_lineno) = opline->lineno;
2340            zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
2341        } else {
2342            /* Label is not defined. Delay to pass 2. */
2343            INC_BPC(op_array);
2344            return;
2345        }
2346    }
2347
2348    opline->op1.opline_num = dest->opline_num;
2349    zval_dtor(label);
2350    Z_TYPE_P(label) = IS_NULL;
2351
2352    /* Check that we are not moving into loop or switch */
2353    current = opline->extended_value;
2354    for (distance = 0; current != dest->brk_cont; distance++) {
2355        if (current == -1) {
2356            if (pass2) {
2357                CG(in_compilation) = 1;
2358                CG(active_op_array) = op_array;
2359                CG(zend_lineno) = opline->lineno;
2360            }
2361            zend_error(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
2362        }
2363        current = op_array->brk_cont_array[current].parent;
2364    }
2365
2366    if (distance == 0) {
2367        /* Nothing to break out of, optimize to ZEND_JMP */
2368        opline->opcode = ZEND_JMP;
2369        opline->extended_value = 0;
2370        SET_UNUSED(opline->op2);
2371    } else {
2372        /* Set real break distance */
2373        ZVAL_LONG(label, distance);
2374    }
2375
2376    if (pass2) {
2377        DEC_BPC(op_array);
2378    }
2379}
2380/* }}} */
2381
2382void zend_do_goto(const znode *label TSRMLS_DC) /* {{{ */
2383{
2384    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2385
2386    opline->opcode = ZEND_GOTO;
2387    opline->extended_value = CG(context).current_brk_cont;
2388    SET_UNUSED(opline->op1);
2389    SET_NODE(opline->op2, label);
2390    zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC);
2391}
2392/* }}} */
2393
2394void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
2395{
2396    if (CG(context).labels) {
2397        zend_hash_destroy(CG(context).labels);
2398        FREE_HASHTABLE(CG(context).labels);
2399        CG(context).labels = NULL;
2400    }
2401    if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
2402        zend_compiler_context *ctx;
2403
2404        zend_stack_top(&CG(context_stack), (void**)&ctx);
2405        CG(context) = *ctx;
2406        zend_stack_del_top(&CG(context_stack));
2407    }
2408}
2409/* }}} */
2410
2411void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC) /* {{{ */
2412{
2413    zend_uint length;
2414
2415    if (!result) {
2416        result = prefix;
2417    } else {
2418        *result = *prefix;
2419    }
2420
2421    if (is_class_member) {
2422        length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2423        result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2424        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1);
2425        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2426        STR_FREE(name->u.constant.value.str.val);
2427        result->u.constant.value.str.len = length;
2428    } else {
2429        length = sizeof("\\")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2430        result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2431        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "\\", sizeof("\\")-1);
2432        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("\\")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2433        STR_FREE(name->u.constant.value.str.val);
2434        result->u.constant.value.str.len = length;
2435    }
2436}
2437/* }}} */
2438
2439int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
2440{
2441    znode class_node;
2442    unsigned char *ptr = NULL;
2443    zend_op *opline;
2444
2445    if (method_name->op_type == IS_CONST) {
2446        char *lcname;
2447        if (Z_TYPE(method_name->u.constant) != IS_STRING) {
2448            zend_error(E_COMPILE_ERROR, "Method name must be a string");
2449        }
2450        lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant));
2451        if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) &&
2452            memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) {
2453            zval_dtor(&method_name->u.constant);
2454            method_name->op_type = IS_UNUSED;
2455        }
2456        efree(lcname);
2457    }
2458
2459    if (class_name->op_type == IS_CONST &&
2460        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2461        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2462        class_node = *class_name;
2463        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2464    } else {
2465        zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
2466        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2467        opline->extended_value = class_node.EA  ;
2468    }
2469    opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
2470    opline->result.num = CG(context).nested_calls;
2471    if (class_node.op_type == IS_CONST) {
2472        opline->op1_type = IS_CONST;
2473        opline->op1.constant =
2474            zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
2475    } else {
2476        SET_NODE(opline->op1, &class_node);
2477    }
2478    if (method_name->op_type == IS_CONST) {
2479        opline->op2_type = IS_CONST;
2480        opline->op2.constant =
2481            zend_add_func_name_literal(CG(active_op_array), &method_name->u.constant TSRMLS_CC);
2482        if (opline->op1_type == IS_CONST) {
2483            GET_CACHE_SLOT(opline->op2.constant);
2484        } else {
2485            GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
2486        }
2487    } else {
2488        SET_NODE(opline->op2, method_name);
2489    }
2490
2491    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2492    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2493        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2494    }
2495    zend_do_extended_fcall_begin(TSRMLS_C);
2496    return 1; /* Dynamic */
2497}
2498/* }}} */
2499
2500void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
2501{
2502    zend_op *opline;
2503
2504    if (is_method && function_name && function_name->op_type == IS_UNUSED) {
2505        /* clone */
2506        if (Z_LVAL(argument_list->u.constant) != 0) {
2507            zend_error(E_WARNING, "Clone method does not require arguments");
2508        }
2509        opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
2510    } else {
2511        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2512        if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
2513            opline->opcode = ZEND_DO_FCALL;
2514            SET_NODE(opline->op1, function_name);
2515            SET_UNUSED(opline->op2);
2516            opline->op2.num = CG(context).nested_calls;
2517            CALCULATE_LITERAL_HASH(opline->op1.constant);
2518            GET_CACHE_SLOT(opline->op1.constant);
2519        } else {
2520            opline->opcode = ZEND_DO_FCALL_BY_NAME;
2521            SET_UNUSED(opline->op1);
2522            SET_UNUSED(opline->op2);
2523            opline->op2.num = --CG(context).nested_calls;
2524        }
2525    }
2526
2527    opline->result.var = get_temporary_variable(CG(active_op_array));
2528    opline->result_type = IS_VAR;
2529    GET_NODE(result, opline->result);
2530
2531    zend_stack_del_top(&CG(function_call_stack));
2532    opline->extended_value = Z_LVAL(argument_list->u.constant);
2533
2534    if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
2535        CG(active_op_array)->used_stack = CG(context).used_stack + 1;
2536    }
2537    CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
2538}
2539/* }}} */
2540
2541void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */
2542{
2543    zend_op *opline;
2544    int original_op=op;
2545    zend_function **function_ptr_ptr, *function_ptr;
2546    int send_by_reference;
2547    int send_function = 0;
2548
2549    zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
2550    function_ptr = *function_ptr_ptr;
2551
2552    if (original_op == ZEND_SEND_REF) {
2553        if (function_ptr &&
2554            function_ptr->common.function_name &&
2555            function_ptr->common.type == ZEND_USER_FUNCTION &&
2556            !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2557            zend_error(E_COMPILE_ERROR,
2558                        "Call-time pass-by-reference has been removed; "
2559                        "If you would like to pass argument by reference, modify the declaration of %s().",
2560                        function_ptr->common.function_name);
2561        } else {
2562            zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed");
2563        }
2564        return;
2565    }
2566
2567    if (function_ptr) {
2568        if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2569            if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
2570                send_by_reference = 1;
2571                if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2572                    /* Method call */
2573                    op = ZEND_SEND_VAR_NO_REF;
2574                    send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT;
2575                }
2576            } else {
2577                op = ZEND_SEND_VAL;
2578                send_by_reference = 0;
2579            }
2580        } else {
2581            send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0;
2582        }
2583    } else {
2584        send_by_reference = 0;
2585    }
2586
2587    if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2588        /* Method call */
2589        op = ZEND_SEND_VAR_NO_REF;
2590        send_function = ZEND_ARG_SEND_FUNCTION;
2591    } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) {
2592        op = ZEND_SEND_VAR_NO_REF;
2593    }
2594
2595    if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) {
2596        /* change to passing by reference */
2597        switch (param->op_type) {
2598            case IS_VAR:
2599            case IS_CV:
2600                op = ZEND_SEND_REF;
2601                break;
2602            default:
2603                zend_error(E_COMPILE_ERROR, "Only variables can be passed by reference");
2604                break;
2605        }
2606    }
2607
2608    if (original_op == ZEND_SEND_VAR) {
2609        switch (op) {
2610            case ZEND_SEND_VAR_NO_REF:
2611                zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2612                break;
2613            case ZEND_SEND_VAR:
2614                if (function_ptr) {
2615                    zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2616                } else {
2617                    zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC);
2618                }
2619                break;
2620            case ZEND_SEND_REF:
2621                zend_do_end_variable_parse(param, BP_VAR_W, 0 TSRMLS_CC);
2622                break;
2623        }
2624    }
2625
2626    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2627
2628    if (op == ZEND_SEND_VAR_NO_REF) {
2629        if (function_ptr) {
2630            opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference | send_function;
2631        } else {
2632            opline->extended_value = send_function;
2633        }
2634    } else {
2635        if (function_ptr) {
2636            opline->extended_value = ZEND_DO_FCALL;
2637        } else {
2638            opline->extended_value = ZEND_DO_FCALL_BY_NAME;
2639        }
2640    }
2641    opline->opcode = op;
2642    SET_NODE(opline->op1, param);
2643    opline->op2.opline_num = offset;
2644    SET_UNUSED(opline->op2);
2645
2646    if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
2647        CG(active_op_array)->used_stack = CG(context).used_stack;
2648    }
2649}
2650/* }}} */
2651
2652static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */
2653{
2654    zend_op *opline;
2655
2656    if (switch_entry->cond.op_type != IS_VAR && switch_entry->cond.op_type != IS_TMP_VAR) {
2657        return (switch_entry->cond.op_type == IS_UNUSED);
2658    }
2659
2660    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2661
2662    opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2663    SET_NODE(opline->op1, &switch_entry->cond);
2664    SET_UNUSED(opline->op2);
2665
2666    return 0;
2667}
2668/* }}} */
2669
2670static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /* {{{ */
2671{
2672    zend_op *opline;
2673
2674    /* If we reach the separator then stop applying the stack */
2675    if (foreach_copy->result_type == IS_UNUSED) {
2676        return 1;
2677    }
2678
2679    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2680
2681    opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2682    COPY_NODE(opline->op1, foreach_copy->result);
2683    SET_UNUSED(opline->op2);
2684
2685    return 0;
2686}
2687/* }}} */
2688
2689void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
2690{
2691    zend_op *opline;
2692    int start_op_number, end_op_number;
2693    zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2694
2695    /* The error for use of return inside a generator is thrown in pass_two. */
2696
2697    if (do_end_vparse) {
2698        if (returns_reference && !zend_is_function_or_method_call(expr)) {
2699            zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
2700        } else {
2701            zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);
2702        }
2703    }
2704
2705    start_op_number = get_next_op_number(CG(active_op_array));
2706
2707#ifdef ZTS
2708    zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC);
2709    zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC);
2710#else
2711    zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr);
2712    zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
2713#endif
2714
2715    end_op_number = get_next_op_number(CG(active_op_array));
2716    while (start_op_number < end_op_number) {
2717        CG(active_op_array)->opcodes[start_op_number].extended_value |= EXT_TYPE_FREE_ON_RETURN;
2718        start_op_number++;
2719    }
2720
2721    if (CG(context).in_finally) {
2722        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2723        opline->opcode = ZEND_DISCARD_EXCEPTION;
2724        SET_UNUSED(opline->op1);
2725        SET_UNUSED(opline->op2);
2726    }
2727
2728    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2729
2730    opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
2731
2732    if (expr) {
2733        SET_NODE(opline->op1, expr);
2734
2735        if (do_end_vparse && zend_is_function_or_method_call(expr)) {
2736            opline->extended_value = ZEND_RETURNS_FUNCTION;
2737        }
2738    } else {
2739        opline->op1_type = IS_CONST;
2740        LITERAL_NULL(opline->op1);
2741    }
2742
2743    SET_UNUSED(opline->op2);
2744}
2745/* }}} */
2746
2747void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC) /* {{{ */
2748{
2749    zend_op *opline;
2750
2751    if (!CG(active_op_array)->function_name) {
2752        zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
2753    }
2754
2755    CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
2756
2757    if (is_variable) {
2758        if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(value)) {
2759            zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
2760        } else {
2761            zend_do_end_variable_parse(value, BP_VAR_R, 0 TSRMLS_CC);
2762        }
2763    }
2764
2765    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2766
2767    opline->opcode = ZEND_YIELD;
2768
2769    if (value) {
2770        SET_NODE(opline->op1, value);
2771
2772        if (is_variable && zend_is_function_or_method_call(value)) {
2773            opline->extended_value = ZEND_RETURNS_FUNCTION;
2774        }
2775    } else {
2776        SET_UNUSED(opline->op1);
2777    }
2778
2779    if (key) {
2780        SET_NODE(opline->op2, key);
2781    } else {
2782        SET_UNUSED(opline->op2);
2783    }
2784
2785    opline->result_type = IS_VAR;
2786    opline->result.var = get_temporary_variable(CG(active_op_array));
2787    GET_NODE(result, opline->result);
2788}
2789/* }}} */
2790
2791static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
2792{
2793    int try_catch_offset = CG(active_op_array)->last_try_catch++;
2794
2795    CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
2796    CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
2797    CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0;
2798    CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
2799    CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
2800    return try_catch_offset;
2801}
2802/* }}} */
2803
2804static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC) /* {{{ */
2805{
2806    CG(active_op_array)->try_catch_array[offset].catch_op = catch_op;
2807}
2808/* }}} */
2809
2810void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */
2811{
2812    open_parentheses->u.op.opline_num = get_next_op_number(CG(active_op_array));
2813}
2814/* }}} */
2815
2816void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */
2817{
2818    int jmp_op_number = get_next_op_number(CG(active_op_array));
2819    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2820    zend_llist jmp_list;
2821    zend_llist *jmp_list_ptr;
2822
2823    opline->opcode = ZEND_JMP;
2824    SET_UNUSED(opline->op1);
2825    SET_UNUSED(opline->op2);
2826    /* save for backpatching */
2827
2828    zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
2829    zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
2830    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2831    zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2832
2833    catch_token->EA = get_next_op_number(CG(active_op_array));
2834}
2835/* }}} */
2836
2837void zend_do_mark_last_catch(const znode *first_catch, const znode *last_additional_catch TSRMLS_DC) /* {{{ */
2838{
2839    CG(active_op_array)->last--;
2840    zend_do_if_end(TSRMLS_C);
2841    if (last_additional_catch->u.op.opline_num == -1) {
2842        CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1;
2843        CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2844    } else {
2845        CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].result.num = 1;
2846        CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2847    }
2848    DEC_BPC(CG(active_op_array));
2849}
2850/* }}} */
2851
2852void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */
2853{
2854    try_token->u.op.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC);
2855    INC_BPC(CG(active_op_array));
2856}
2857/* }}} */
2858
2859void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */
2860{
2861    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2862
2863    finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
2864    /* call the the "finally" block */
2865    opline->opcode = ZEND_FAST_CALL;
2866    SET_UNUSED(opline->op1);
2867    opline->op1.opline_num = finally_token->u.op.opline_num + 1;
2868    SET_UNUSED(opline->op2);
2869    /* jump to code after the "finally" block,
2870     * the actual jump address is going to be set in zend_do_end_finally()
2871     */
2872    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2873    opline->opcode = ZEND_JMP;
2874    SET_UNUSED(opline->op1);
2875    SET_UNUSED(opline->op2);
2876
2877    CG(context).in_finally++;
2878}
2879/* }}} */
2880
2881void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
2882{
2883    long catch_op_number;
2884    zend_op *opline;
2885    znode catch_class;
2886
2887    if (class_name->op_type == IS_CONST &&
2888        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2889        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2890        catch_class = *class_name;
2891    } else {
2892        zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
2893    }
2894
2895    catch_op_number = get_next_op_number(CG(active_op_array));
2896    if (first_catch) {
2897        first_catch->u.op.opline_num = catch_op_number;
2898    }
2899
2900    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2901    opline->opcode = ZEND_CATCH;
2902    opline->op1_type = IS_CONST;
2903    opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC);
2904    opline->op2_type = IS_CV;
2905    opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len, 0 TSRMLS_CC);
2906    Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
2907    opline->result.num = 0; /* 1 means it's the last catch in the block */
2908
2909    catch_token->u.op.opline_num = catch_op_number;
2910}
2911/* }}} */
2912
2913void zend_do_end_catch(znode *catch_token TSRMLS_DC) /* {{{ */
2914{
2915    int jmp_op_number = get_next_op_number(CG(active_op_array));
2916    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2917    zend_llist *jmp_list_ptr;
2918
2919    opline->opcode = ZEND_JMP;
2920    SET_UNUSED(opline->op1);
2921    SET_UNUSED(opline->op2);
2922    /* save for backpatching */
2923
2924    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2925    zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2926
2927    CG(active_op_array)->opcodes[catch_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2928}
2929/* }}} */
2930
2931void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ */ {
2932    if (catch_token->op_type != IS_UNUSED) {
2933        zend_add_catch_element(try_token->u.op.opline_num, catch_token->EA TSRMLS_CC);
2934    }
2935}
2936/* }}} */
2937
2938void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */
2939{
2940    if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
2941        zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
2942    }
2943    if (finally_token->op_type != IS_UNUSED) {
2944        zend_op *opline;
2945
2946        CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
2947        CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
2948        CG(active_op_array)->has_finally_block = 1;
2949
2950        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2951        opline->opcode = ZEND_FAST_RET;
2952        SET_UNUSED(opline->op1);
2953        SET_UNUSED(opline->op2);
2954
2955        CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
2956
2957        CG(context).in_finally--;
2958    }
2959}
2960/* }}} */
2961
2962void zend_do_throw(const znode *expr TSRMLS_DC) /* {{{ */
2963{
2964    zend_op *opline;
2965
2966    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2967    opline->opcode = ZEND_THROW;
2968    SET_NODE(opline->op1, expr);
2969    SET_UNUSED(opline->op2);
2970}
2971/* }}} */
2972
2973ZEND_API void function_add_ref(zend_function *function) /* {{{ */
2974{
2975    if (function->type == ZEND_USER_FUNCTION) {
2976        zend_op_array *op_array = &function->op_array;
2977
2978        (*op_array->refcount)++;
2979        if (op_array->static_variables) {
2980            HashTable *static_variables = op_array->static_variables;
2981            zval *tmp_zval;
2982
2983            ALLOC_HASHTABLE(op_array->static_variables);
2984            zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
2985            zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *));
2986        }
2987        op_array->run_time_cache = NULL;
2988    }
2989}
2990/* }}} */
2991
2992static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
2993{
2994    zend_function *function, *new_function;
2995
2996    if (!ce->parent) {
2997        return;
2998    }
2999
3000    /* You cannot change create_object */
3001    ce->create_object = ce->parent->create_object;
3002
3003    /* Inherit special functions if needed */
3004    if (!ce->get_iterator) {
3005        ce->get_iterator = ce->parent->get_iterator;
3006    }
3007    if (!ce->iterator_funcs.funcs) {
3008        ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
3009    }
3010    if (!ce->__get) {
3011        ce->__get   = ce->parent->__get;
3012    }
3013    if (!ce->__set) {
3014        ce->__set = ce->parent->__set;
3015    }
3016    if (!ce->__unset) {
3017        ce->__unset = ce->parent->__unset;
3018    }
3019    if (!ce->__isset) {
3020        ce->__isset = ce->parent->__isset;
3021    }
3022    if (!ce->__call) {
3023        ce->__call = ce->parent->__call;
3024    }
3025    if (!ce->__callstatic) {
3026        ce->__callstatic = ce->parent->__callstatic;
3027    }
3028    if (!ce->__tostring) {
3029        ce->__tostring = ce->parent->__tostring;
3030    }
3031    if (!ce->clone) {
3032        ce->clone = ce->parent->clone;
3033    }
3034    if(!ce->serialize) {
3035        ce->serialize = ce->parent->serialize;
3036    }
3037    if(!ce->unserialize) {
3038        ce->unserialize = ce->parent->unserialize;
3039    }
3040    if (!ce->destructor) {
3041        ce->destructor   = ce->parent->destructor;
3042    }
3043    if (ce->constructor) {
3044        if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
3045            zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
3046                ce->parent->name, ce->parent->constructor->common.function_name,
3047                ce->name, ce->constructor->common.function_name
3048                );
3049        }
3050        return;
3051    }
3052
3053    if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) {
3054        /* inherit parent's constructor */
3055        zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function);
3056        function_add_ref(new_function);
3057    } else {
3058        /* Don't inherit the old style constructor if we already have the new style constructor */
3059        char *lc_class_name;
3060        char *lc_parent_class_name;
3061
3062        lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
3063        if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
3064            lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
3065            if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
3066                    zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
3067                if (function->common.fn_flags & ZEND_ACC_CTOR) {
3068                    /* inherit parent's constructor */
3069                    zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function);
3070                    function_add_ref(new_function);
3071                }
3072            }
3073            efree(lc_parent_class_name);
3074        }
3075        efree(lc_class_name);
3076    }
3077    ce->constructor = ce->parent->constructor;
3078}
3079/* }}} */
3080
3081char *zend_visibility_string(zend_uint fn_flags) /* {{{ */
3082{
3083    if (fn_flags & ZEND_ACC_PRIVATE) {
3084        return "private";
3085    }
3086    if (fn_flags & ZEND_ACC_PROTECTED) {
3087        return "protected";
3088    }
3089    if (fn_flags & ZEND_ACC_PUBLIC) {
3090        return "public";
3091    }
3092    return "";
3093}
3094/* }}} */
3095
3096static void do_inherit_method(zend_function *function) /* {{{ */
3097{
3098    /* The class entry of the derived function intentionally remains the same
3099     * as that of the parent class.  That allows us to know in which context
3100     * we're running, and handle private method calls properly.
3101     */
3102    function_add_ref(function);
3103}
3104/* }}} */
3105
3106static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
3107{
3108    zend_uint i;
3109
3110    /* If it's a user function then arg_info == NULL means we don't have any parameters but
3111     * we still need to do the arg number checks.  We are only willing to ignore this for internal
3112     * functions because extensions don't always define arg_info.
3113     */
3114    if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
3115        return 1;
3116    }
3117
3118    /* Checks for constructors only if they are declared in an interface,
3119     * or explicitly marked as abstract
3120     */
3121    if ((fe->common.fn_flags & ZEND_ACC_CTOR)
3122        && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3123            && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
3124        return 1;
3125    }
3126
3127    /* If both methods are private do not enforce a signature */
3128    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
3129        return 1;
3130    }
3131
3132    /* check number of arguments */
3133    if (proto->common.required_num_args < fe->common.required_num_args
3134        || proto->common.num_args > fe->common.num_args) {
3135        return 0;
3136    }
3137
3138    if (fe->common.type != ZEND_USER_FUNCTION
3139        && (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0
3140        && (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) {
3141        return 0;
3142    }
3143
3144    /* by-ref constraints on return values are covariant */
3145    if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
3146        && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
3147        return 0;
3148    }
3149
3150    for (i=0; i < proto->common.num_args; i++) {
3151        if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) {
3152            /* Only one has a type hint and the other one doesn't */
3153            return 0;
3154        }
3155
3156        if (fe->common.arg_info[i].class_name) {
3157            const char *fe_class_name, *proto_class_name;
3158            zend_uint fe_class_name_len, proto_class_name_len;
3159
3160            if (!strcasecmp(fe->common.arg_info[i].class_name, "parent") && proto->common.scope) {
3161                fe_class_name = proto->common.scope->name;
3162                fe_class_name_len = proto->common.scope->name_length;
3163            } else if (!strcasecmp(fe->common.arg_info[i].class_name, "self") && fe->common.scope) {
3164                fe_class_name = fe->common.scope->name;
3165                fe_class_name_len = fe->common.scope->name_length;
3166            } else {
3167                fe_class_name = fe->common.arg_info[i].class_name;
3168                fe_class_name_len = fe->common.arg_info[i].class_name_len;
3169            }
3170
3171            if (!strcasecmp(proto->common.arg_info[i].class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
3172                proto_class_name = proto->common.scope->parent->name;
3173                proto_class_name_len = proto->common.scope->parent->name_length;
3174            } else if (!strcasecmp(proto->common.arg_info[i].class_name, "self") && proto->common.scope) {
3175                proto_class_name = proto->common.scope->name;
3176                proto_class_name_len = proto->common.scope->name_length;
3177            } else {
3178                proto_class_name = proto->common.arg_info[i].class_name;
3179                proto_class_name_len = proto->common.arg_info[i].class_name_len;
3180            }
3181
3182            if (strcasecmp(fe_class_name, proto_class_name)!=0) {
3183                const char *colon;
3184
3185                if (fe->common.type != ZEND_USER_FUNCTION) {
3186                    return 0;
3187                } else if (strchr(proto_class_name, '\\') != NULL ||
3188                        (colon = zend_memrchr(fe_class_name, '\\', fe_class_name_len)) == NULL ||
3189                        strcasecmp(colon+1, proto_class_name) != 0) {
3190                    zend_class_entry **fe_ce, **proto_ce;
3191                    int found, found2;
3192
3193                    found = zend_lookup_class(fe_class_name, fe_class_name_len, &fe_ce TSRMLS_CC);
3194                    found2 = zend_lookup_class(proto_class_name, proto_class_name_len, &proto_ce TSRMLS_CC);
3195
3196                    /* Check for class alias */
3197                    if (found != SUCCESS || found2 != SUCCESS ||
3198                            (*fe_ce)->type == ZEND_INTERNAL_CLASS ||
3199                            (*proto_ce)->type == ZEND_INTERNAL_CLASS ||
3200                            *fe_ce != *proto_ce) {
3201                        return 0;
3202                    }
3203                }
3204            }
3205        }
3206        if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
3207            /* Incompatible type hint */
3208            return 0;
3209        }
3210
3211        /* by-ref constraints on arguments are invariant */
3212        if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
3213            return 0;
3214        }
3215    }
3216
3217    if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) {
3218        for (i=proto->common.num_args; i < fe->common.num_args; i++) {
3219            if (!fe->common.arg_info[i].pass_by_reference) {
3220                return 0;
3221            }
3222        }
3223    }
3224    return 1;
3225}
3226/* }}} */
3227
3228#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
3229    if (UNEXPECTED(offset - buf + size >= length)) {    \
3230        length += size + 1;                 \
3231        buf = erealloc(buf, length);        \
3232    }
3233
3234static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
3235{
3236    char *offset, *buf;
3237    zend_uint length = 1024;
3238
3239    offset = buf = (char *)emalloc(length * sizeof(char));
3240    if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3241        *(offset++) = '&';
3242        *(offset++) = ' ';
3243    }
3244
3245    if (fptr->common.scope) {
3246        memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length);
3247        offset += fptr->common.scope->name_length;
3248        *(offset++) = ':';
3249        *(offset++) = ':';
3250    }
3251
3252    {
3253        size_t name_len = strlen(fptr->common.function_name);
3254        REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
3255        memcpy(offset, fptr->common.function_name, name_len);
3256        offset += name_len;
3257    }
3258
3259    *(offset++) = '(';
3260    if (fptr->common.arg_info) {
3261        zend_uint i, required;
3262        zend_arg_info *arg_info = fptr->common.arg_info;
3263
3264        required = fptr->common.required_num_args;
3265        for (i = 0; i < fptr->common.num_args;) {
3266            if (arg_info->class_name) {
3267                const char *class_name;
3268                zend_uint class_name_len;
3269                if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
3270                    class_name = fptr->common.scope->name;
3271                    class_name_len = fptr->common.scope->name_length;
3272                } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
3273                    class_name = fptr->common.scope->parent->name;
3274                    class_name_len = fptr->common.scope->parent->name_length;
3275                } else {
3276                    class_name = arg_info->class_name;
3277                    class_name_len = arg_info->class_name_len;
3278                }
3279                REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
3280                memcpy(offset, class_name, class_name_len);
3281                offset += class_name_len;
3282                *(offset++) = ' ';
3283            } else if (arg_info->type_hint) {
3284                zend_uint type_name_len;
3285                char *type_name = zend_get_type_by_const(arg_info->type_hint);
3286                type_name_len = strlen(type_name);
3287                REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
3288                memcpy(offset, type_name, type_name_len);
3289                offset += type_name_len;
3290                *(offset++) = ' ';
3291            }
3292
3293            if (arg_info->pass_by_reference) {
3294                *(offset++) = '&';
3295            }
3296            *(offset++) = '$';
3297
3298            if (arg_info->name) {
3299                REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
3300                memcpy(offset, arg_info->name, arg_info->name_len);
3301                offset += arg_info->name_len;
3302            } else {
3303                zend_uint idx = i;
3304                memcpy(offset, "param", 5);
3305                offset += 5;
3306                do {
3307                    *(offset++) = (char) (idx % 10) + '0';
3308                    idx /= 10;
3309                } while (idx > 0);
3310            }
3311            if (i >= required) {
3312                *(offset++) = ' ';
3313                *(offset++) = '=';
3314                *(offset++) = ' ';
3315                if (fptr->type == ZEND_USER_FUNCTION) {
3316                    zend_op *precv = NULL;
3317                    {
3318                        zend_uint idx  = i;
3319                        zend_op *op = ((zend_op_array *)fptr)->opcodes;
3320                        zend_op *end = op + ((zend_op_array *)fptr)->last;
3321
3322                        ++idx;
3323                        while (op < end) {
3324                            if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
3325                                    && op->op1.num == (long)idx)
3326                            {
3327                                precv = op;
3328                            }
3329                            ++op;
3330                        }
3331                    }
3332                    if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
3333                        zval *zv, zv_copy;
3334                        int use_copy;
3335                        ALLOC_ZVAL(zv);
3336                        *zv = *precv->op2.zv;
3337                        zval_copy_ctor(zv);
3338                        INIT_PZVAL(zv);
3339                        zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
3340                        if (Z_TYPE_P(zv) == IS_BOOL) {
3341                            if (Z_LVAL_P(zv)) {
3342                                memcpy(offset, "true", 4);
3343                                offset += 4;
3344                            } else {
3345                                memcpy(offset, "false", 5);
3346                                offset += 5;
3347                            }
3348                        } else if (Z_TYPE_P(zv) == IS_NULL) {
3349                            memcpy(offset, "NULL", 4);
3350                            offset += 4;
3351                        } else if (Z_TYPE_P(zv) == IS_STRING) {
3352                            *(offset++) = '\'';
3353                            REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
3354                            memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
3355                            offset += MIN(Z_STRLEN_P(zv), 10);
3356                            if (Z_STRLEN_P(zv) > 10) {
3357                                *(offset++) = '.';
3358                                *(offset++) = '.';
3359                                *(offset++) = '.';
3360                            }
3361                            *(offset++) = '\'';
3362                        } else if (Z_TYPE_P(zv) == IS_ARRAY) {
3363                            memcpy(offset, "Array", 5);
3364                            offset += 5;
3365                        } else {
3366                            zend_make_printable_zval(zv, &zv_copy, &use_copy);
3367                            REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN(zv_copy));
3368                            memcpy(offset, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
3369                            offset += Z_STRLEN(zv_copy);
3370                            if (use_copy) {
3371                                zval_dtor(&zv_copy);
3372                            }
3373                        }
3374                        zval_ptr_dtor(&zv);
3375                    }
3376                } else {
3377                    memcpy(offset, "NULL", 4);
3378                    offset += 4;
3379                }
3380            }
3381
3382            if (++i < fptr->common.num_args) {
3383                *(offset++) = ',';
3384                *(offset++) = ' ';
3385            }
3386            arg_info++;
3387            REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
3388        }
3389    }
3390    *(offset++) = ')';
3391    *offset = '\0';
3392
3393    return buf;
3394}
3395/* }}} */
3396
3397static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
3398{
3399    zend_uint child_flags;
3400    zend_uint parent_flags = parent->common.fn_flags;
3401
3402    if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3403        && parent->common.fn_flags & ZEND_ACC_ABSTRACT
3404        && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
3405        && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
3406        zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
3407            parent->common.scope->name,
3408            child->common.function_name,
3409            child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);
3410    }
3411
3412    if (parent_flags & ZEND_ACC_FINAL) {
3413        zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name);
3414    }
3415
3416    child_flags = child->common.fn_flags;
3417    /* You cannot change from static to non static and vice versa.
3418     */
3419    if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
3420        if (child->common.fn_flags & ZEND_ACC_STATIC) {
3421            zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3422        } else {
3423            zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3424        }
3425    }
3426
3427    /* Disallow making an inherited method abstract. */
3428    if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
3429        zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3430    }
3431
3432    if (parent_flags & ZEND_ACC_CHANGED) {
3433        child->common.fn_flags |= ZEND_ACC_CHANGED;
3434    } else {
3435        /* Prevent derived classes from restricting access that was available in parent classes
3436         */
3437        if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
3438            zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
3439        } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
3440            && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
3441            child->common.fn_flags |= ZEND_ACC_CHANGED;
3442        }
3443    }
3444
3445    if (parent_flags & ZEND_ACC_PRIVATE) {
3446        child->common.prototype = NULL;
3447    } else if (parent_flags & ZEND_ACC_ABSTRACT) {
3448        child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
3449        child->common.prototype = parent;
3450    } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
3451        /* ctors only have a prototype if it comes from an interface */
3452        child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
3453    }
3454
3455    if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3456        if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
3457            zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
3458        }
3459    } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
3460        if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
3461            char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
3462            zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
3463            efree(method_prototype);
3464        }
3465    }
3466}
3467/* }}} */
3468
3469static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, const zend_hash_key *hash_key, zend_class_entry *child_ce) /* {{{ */
3470{
3471    zend_uint parent_flags = parent->common.fn_flags;
3472    zend_function *child;
3473    TSRMLS_FETCH();
3474
3475    if (zend_hash_quick_find(child_function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) {
3476        if (parent_flags & (ZEND_ACC_ABSTRACT)) {
3477            child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3478        }
3479        return 1; /* method doesn't exist in child, copy from parent */
3480    }
3481
3482    do_inheritance_check_on_method(child, parent TSRMLS_CC);
3483
3484    return 0;
3485}
3486/* }}} */
3487
3488static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, const zend_hash_key *hash_key, zend_class_entry *ce) /* {{{ */
3489{
3490    zend_property_info *child_info;
3491    zend_class_entry *parent_ce = ce->parent;
3492
3493    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
3494        if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3495            child_info->flags |= ZEND_ACC_CHANGED;
3496        } else {
3497            zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info);
3498            if(ce->type & ZEND_INTERNAL_CLASS) {
3499                zend_duplicate_property_info_internal(child_info);
3500            } else {
3501                zend_duplicate_property_info(child_info);
3502            }
3503            child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
3504            child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
3505        }
3506        return 0; /* don't copy access information to child */
3507    }
3508
3509    if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3510        if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
3511            zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
3512                (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,
3513                (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
3514
3515        }
3516
3517        if(parent_info->flags & ZEND_ACC_CHANGED) {
3518            child_info->flags |= ZEND_ACC_CHANGED;
3519        }
3520
3521        if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
3522            zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
3523        } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
3524            zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
3525            ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
3526            ce->default_properties_table[child_info->offset] = NULL;
3527            child_info->offset = parent_info->offset;
3528        }
3529        return 0;   /* Don't copy from parent */
3530    } else {
3531        return 1;   /* Copy from parent */
3532    }
3533}
3534/* }}} */
3535
3536static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3537{
3538    if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
3539        zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name);
3540    }
3541    if (ce == iface) {
3542        zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name);
3543    }
3544}
3545/* }}} */
3546
3547ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
3548{
3549    /* expects interface to be contained in ce's interface list already */
3550    zend_uint i, ce_num, if_num = iface->num_interfaces;
3551    zend_class_entry *entry;
3552
3553    if (if_num==0) {
3554        return;
3555    }
3556    ce_num = ce->num_interfaces;
3557
3558    if (ce->type == ZEND_INTERNAL_CLASS) {
3559        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3560    } else {
3561        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3562    }
3563
3564    /* Inherit the interfaces, only if they're not already inherited by the class */
3565    while (if_num--) {
3566        entry = iface->interfaces[if_num];
3567        for (i = 0; i < ce_num; i++) {
3568            if (ce->interfaces[i] == entry) {
3569                break;
3570            }
3571        }
3572        if (i == ce_num) {
3573            ce->interfaces[ce->num_interfaces++] = entry;
3574        }
3575    }
3576
3577    /* and now call the implementing handlers */
3578    while (ce_num < ce->num_interfaces) {
3579        do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
3580    }
3581}
3582/* }}} */
3583
3584#ifdef ZTS
3585static void zval_internal_ctor(zval **p) /* {{{ */
3586{
3587    zval *orig_ptr = *p;
3588
3589    ALLOC_ZVAL(*p);
3590    MAKE_COPY_ZVAL(&orig_ptr, *p);
3591}
3592/* }}} */
3593
3594# define zval_property_ctor(parent_ce, ce) \
3595    ((void (*)(void *)) (((parent_ce)->type != (ce)->type) ? zval_internal_ctor : zval_add_ref))
3596#else
3597# define zval_property_ctor(parent_ce, ce) \
3598    ((void (*)(void *)) zval_add_ref)
3599#endif
3600
3601ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
3602{
3603    zend_property_info *property_info;
3604
3605    if ((ce->ce_flags & ZEND_ACC_INTERFACE)
3606        && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
3607        zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
3608    }
3609    if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
3610        zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name);
3611    }
3612
3613    ce->parent = parent_ce;
3614    /* Copy serialize/unserialize callbacks */
3615    if (!ce->serialize) {
3616        ce->serialize   = parent_ce->serialize;
3617    }
3618    if (!ce->unserialize) {
3619        ce->unserialize = parent_ce->unserialize;
3620    }
3621
3622    /* Inherit interfaces */
3623    zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
3624
3625    /* Inherit properties */
3626    if (parent_ce->default_properties_count) {
3627        int i = ce->default_properties_count + parent_ce->default_properties_count;
3628
3629        ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3630        if (ce->default_properties_count) {
3631            while (i-- > parent_ce->default_properties_count) {
3632                ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
3633            }
3634        }
3635        for (i = 0; i < parent_ce->default_properties_count; i++) {
3636            ce->default_properties_table[i] = parent_ce->default_properties_table[i];
3637            if (ce->default_properties_table[i]) {
3638#ifdef ZTS
3639                if (parent_ce->type != ce->type) {
3640                    zval *p;
3641
3642                    ALLOC_ZVAL(p);
3643                    MAKE_COPY_ZVAL(&ce->default_properties_table[i], p);
3644                    ce->default_properties_table[i] = p;
3645                } else {
3646                    Z_ADDREF_P(ce->default_properties_table[i]);
3647                }
3648#else
3649                Z_ADDREF_P(ce->default_properties_table[i]);
3650#endif
3651            }
3652        }
3653        ce->default_properties_count += parent_ce->default_properties_count;
3654    }
3655
3656    if (parent_ce->type != ce->type) {
3657        /* User class extends internal class */
3658        zend_update_class_constants(parent_ce  TSRMLS_CC);
3659        if (parent_ce->default_static_members_count) {
3660            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3661
3662            ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i);
3663            if (ce->default_static_members_count) {
3664                while (i-- > parent_ce->default_static_members_count) {
3665                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3666                }
3667            }
3668            for (i = 0; i < parent_ce->default_static_members_count; i++) {
3669                SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
3670                ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
3671                Z_ADDREF_P(ce->default_static_members_table[i]);
3672            }
3673            ce->default_static_members_count += parent_ce->default_static_members_count;
3674            ce->static_members_table = ce->default_static_members_table;
3675        }
3676    } else {
3677        if (parent_ce->default_static_members_count) {
3678            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3679
3680            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3681            if (ce->default_static_members_count) {
3682                while (i-- > parent_ce->default_static_members_count) {
3683                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3684                }
3685            }
3686            for (i = 0; i < parent_ce->default_static_members_count; i++) {
3687                SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]);
3688                ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
3689                Z_ADDREF_P(ce->default_static_members_table[i]);
3690            }
3691            ce->default_static_members_count += parent_ce->default_static_members_count;
3692            if (ce->type == ZEND_USER_CLASS) {
3693                ce->static_members_table = ce->default_static_members_table;
3694            }
3695        }
3696    }
3697
3698    for (zend_hash_internal_pointer_reset(&ce->properties_info);
3699    zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS;
3700    zend_hash_move_forward(&ce->properties_info)) {
3701        if (property_info->ce == ce) {
3702            if (property_info->flags & ZEND_ACC_STATIC) {
3703                property_info->offset += parent_ce->default_static_members_count;
3704            } else {
3705                property_info->offset += parent_ce->default_properties_count;
3706            }
3707        }
3708    }
3709
3710    zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce);
3711
3712    zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, zval_property_ctor(parent_ce, ce), NULL, sizeof(zval *), 0);
3713    zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
3714    do_inherit_parent_constructor(ce);
3715
3716    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
3717        ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
3718    } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
3719        /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
3720        zend_verify_abstract_class(ce TSRMLS_CC);
3721    }
3722    ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
3723}
3724/* }}} */
3725
3726static zend_bool do_inherit_constant_check(HashTable *child_constants_table, const zval **parent_constant, const zend_hash_key *hash_key, const zend_class_entry *iface) /* {{{ */
3727{
3728    zval **old_constant;
3729
3730    if (zend_hash_quick_find(child_constants_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**)&old_constant) == SUCCESS) {
3731        if (*old_constant != *parent_constant) {
3732            zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", hash_key->arKey, iface->name);
3733        }
3734        return 0;
3735    }
3736    return 1;
3737}
3738/* }}} */
3739
3740static int do_interface_constant_check(zval **val TSRMLS_DC, int num_args, va_list args, const zend_hash_key *key) /* {{{ */
3741{
3742    zend_class_entry **iface = va_arg(args, zend_class_entry**);
3743
3744    do_inherit_constant_check(&(*iface)->constants_table, (const zval **) val, key, *iface);
3745
3746    return ZEND_HASH_APPLY_KEEP;
3747}
3748/* }}} */
3749
3750ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3751{
3752    zend_uint i, ignore = 0;
3753    zend_uint current_iface_num = ce->num_interfaces;
3754    zend_uint parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
3755
3756    for (i = 0; i < ce->num_interfaces; i++) {
3757        if (ce->interfaces[i] == NULL) {
3758            memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
3759            i--;
3760        } else if (ce->interfaces[i] == iface) {
3761            if (i < parent_iface_num) {
3762                ignore = 1;
3763            } else {
3764                zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name);
3765            }
3766        }
3767    }
3768    if (ignore) {
3769        /* Check for attempt to redeclare interface constants */
3770        zend_hash_apply_with_arguments(&ce->constants_table TSRMLS_CC, (apply_func_args_t) do_interface_constant_check, 1, &iface);
3771    } else {
3772        if (ce->num_interfaces >= current_iface_num) {
3773            if (ce->type == ZEND_INTERNAL_CLASS) {
3774                ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3775            } else {
3776                ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3777            }
3778        }
3779        ce->interfaces[ce->num_interfaces++] = iface;
3780
3781        zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
3782        zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
3783
3784        do_implement_interface(ce, iface TSRMLS_CC);
3785        zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
3786    }
3787}
3788/* }}} */
3789
3790ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
3791{
3792    zend_uint i, ignore = 0;
3793    zend_uint current_trait_num = ce->num_traits;
3794    zend_uint parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
3795
3796    for (i = 0; i < ce->num_traits; i++) {
3797        if (ce->traits[i] == NULL) {
3798            memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
3799            i--;
3800        } else if (ce->traits[i] == trait) {
3801            if (i < parent_trait_num) {
3802                ignore = 1;
3803            }
3804        }
3805    }
3806    if (!ignore) {
3807        if (ce->num_traits >= current_trait_num) {
3808            if (ce->type == ZEND_INTERNAL_CLASS) {
3809                ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3810            } else {
3811                ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3812            }
3813        }
3814        ce->traits[ce->num_traits++] = trait;
3815    }
3816}
3817/* }}} */
3818
3819static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
3820{
3821    zend_uint    fn_flags = fn->common.scope->ce_flags;
3822    zend_uint other_flags = other_fn->common.scope->ce_flags;
3823
3824    return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
3825        && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
3826        && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
3827            (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
3828}
3829/* }}} */
3830
3831static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */
3832{
3833    if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {
3834        ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
3835    } else if (!strncmp(mname, ZEND_CONSTRUCTOR_FUNC_NAME, mname_len)) {
3836        if (ce->constructor) {
3837            zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3838        }
3839        ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
3840    } else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME,  mname_len)) {
3841        ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
3842    } else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) {
3843        ce->__get = fe;
3844    } else if (!strncmp(mname, ZEND_SET_FUNC_NAME, mname_len)) {
3845        ce->__set = fe;
3846    } else if (!strncmp(mname, ZEND_CALL_FUNC_NAME, mname_len)) {
3847        ce->__call = fe;
3848    } else if (!strncmp(mname, ZEND_UNSET_FUNC_NAME, mname_len)) {
3849        ce->__unset = fe;
3850    } else if (!strncmp(mname, ZEND_ISSET_FUNC_NAME, mname_len)) {
3851        ce->__isset = fe;
3852    } else if (!strncmp(mname, ZEND_CALLSTATIC_FUNC_NAME, mname_len)) {
3853        ce->__callstatic = fe;
3854    } else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) {
3855        ce->__tostring = fe;
3856    } else if (ce->name_length + 1 == mname_len) {
3857        char *lowercase_name = emalloc(ce->name_length + 1);
3858        zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length);
3859        lowercase_name = (char*)zend_new_interned_string(lowercase_name, ce->name_length + 1, 1 TSRMLS_CC);
3860        if (!memcmp(mname, lowercase_name, mname_len)) {
3861            if (ce->constructor) {
3862                zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3863            }
3864            ce->constructor = fe;
3865            fe->common.fn_flags |= ZEND_ACC_CTOR;
3866        }
3867        str_efree(lowercase_name);
3868    }
3869}
3870/* }}} */
3871
3872static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
3873{
3874    zend_function *existing_fn = NULL;
3875    ulong h = zend_hash_func(arKey, nKeyLength);
3876
3877    if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3878        if (existing_fn->common.scope == ce) {
3879            /* members from the current class override trait methods */
3880            /* use temporary *overriden HashTable to detect hidden conflict */
3881            if (*overriden) {
3882                if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3883                    if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3884                        /* Make sure the trait method is compatible with previosly declared abstract method */
3885                        if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3886                            zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3887                                zend_get_function_declaration(fn TSRMLS_CC),
3888                                zend_get_function_declaration(existing_fn TSRMLS_CC));
3889                        }
3890                    } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3891                        /* Make sure the abstract declaration is compatible with previous declaration */
3892                        if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3893                            zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3894                                zend_get_function_declaration(fn TSRMLS_CC),
3895                                zend_get_function_declaration(existing_fn TSRMLS_CC));
3896                        }
3897                        return;
3898                    }
3899                }
3900            } else {
3901                ALLOC_HASHTABLE(*overriden);
3902                zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
3903            }
3904            zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3905            return;
3906        } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3907            /* Make sure the trait method is compatible with previosly declared abstract method */
3908            if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3909                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3910                    zend_get_function_declaration(fn TSRMLS_CC),
3911                    zend_get_function_declaration(existing_fn TSRMLS_CC));
3912            }
3913        } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3914            /* Make sure the abstract declaration is compatible with previous declaration */
3915            if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3916                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3917                    zend_get_function_declaration(fn TSRMLS_CC),
3918                    zend_get_function_declaration(existing_fn TSRMLS_CC));
3919            }
3920            return;
3921        } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3922            /* two trais can't define the same non-abstract method */
3923#if 1
3924            zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
3925                name, ce->name);
3926#else       /* TODO: better errot message */
3927            zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
3928                fn->common.scope->name, fn->common.function_name,
3929                ce->name, name,
3930                existing_fn->common.scope->name, existing_fn->common.function_name);
3931#endif
3932        } else {
3933            /* inherited members are overridden by members inserted by traits */
3934            /* check whether the trait method fulfills the inheritance requirements */
3935            do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
3936        }
3937    }
3938
3939    function_add_ref(fn);
3940    zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3941    zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
3942}
3943/* }}} */
3944
3945static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
3946{
3947    if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3948
3949        fn->common.scope = ce;
3950
3951        if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3952            ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3953        }
3954        if (fn->op_array.static_variables) {
3955            ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
3956        }
3957    }
3958    return ZEND_HASH_APPLY_KEEP;
3959}
3960/* }}} */
3961
3962static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
3963{
3964    zend_class_entry  *ce;
3965    HashTable         **overriden;
3966    zend_trait_alias  *alias, **alias_ptr;
3967    HashTable         *exclude_table;
3968    char              *lcname;
3969    unsigned int       fnname_len;
3970    zend_function      fn_copy;
3971    void              *dummy;
3972
3973    ce            = va_arg(args, zend_class_entry*);
3974    overriden     = va_arg(args, HashTable**);
3975    exclude_table = va_arg(args, HashTable*);
3976
3977    fnname_len = hash_key->nKeyLength - 1;
3978
3979    /* apply aliases which are qualified with a class name, there should not be any ambiguity */
3980    if (ce->trait_aliases) {
3981        alias_ptr = ce->trait_aliases;
3982        alias = *alias_ptr;
3983        while (alias) {
3984            /* Scope unset or equal to the function we compare to, and the alias applies to fn */
3985            if (alias->alias != NULL
3986                && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
3987                && alias->trait_method->mname_len == fnname_len
3988                && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) {
3989                fn_copy = *fn;
3990
3991                /* if it is 0, no modifieres has been changed */
3992                if (alias->modifiers) {
3993                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
3994                }
3995
3996                lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
3997                zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_CC);
3998                efree(lcname);
3999
4000                /* Record the trait from which this alias was resolved. */
4001                if (!alias->trait_method->ce) {
4002                    alias->trait_method->ce = fn->common.scope;
4003                }
4004            }
4005            alias_ptr++;
4006            alias = *alias_ptr;
4007        }
4008    }
4009
4010    lcname = hash_key->arKey;
4011
4012    if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
4013        /* is not in hashtable, thus, function is not to be excluded */
4014        fn_copy = *fn;
4015
4016        /* apply aliases which have not alias name, just setting visibility */
4017        if (ce->trait_aliases) {
4018            alias_ptr = ce->trait_aliases;
4019            alias = *alias_ptr;
4020            while (alias) {
4021                /* Scope unset or equal to the function we compare to, and the alias applies to fn */
4022                if (alias->alias == NULL && alias->modifiers != 0
4023                    && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
4024                    && (alias->trait_method->mname_len == fnname_len)
4025                    && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, lcname, fnname_len) == 0)) {
4026
4027                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
4028
4029                    /** Record the trait from which this alias was resolved. */
4030                    if (!alias->trait_method->ce) {
4031                        alias->trait_method->ce = fn->common.scope;
4032                    }
4033                }
4034                alias_ptr++;
4035                alias = *alias_ptr;
4036            }
4037        }
4038
4039        zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_CC);
4040    }
4041
4042    return ZEND_HASH_APPLY_KEEP;
4043}
4044/* }}} */
4045
4046static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
4047{
4048    zend_uint i;
4049
4050    if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
4051        zend_error(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name);
4052    }
4053
4054    for (i = 0; i < ce->num_traits; i++) {
4055        if (ce->traits[i] == trait) {
4056            return;
4057        }
4058    }
4059    zend_error(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name, ce->name);
4060}
4061/* }}} */
4062
4063static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4064{
4065    size_t i, j = 0;
4066    zend_trait_precedence *cur_precedence;
4067    zend_trait_method_reference *cur_method_ref;
4068    char *lcname;
4069    zend_bool method_exists;
4070
4071    /* resolve class references */
4072    if (ce->trait_precedences) {
4073        i = 0;
4074        while ((cur_precedence = ce->trait_precedences[i])) {
4075            /** Resolve classes for all precedence operations. */
4076            if (cur_precedence->exclude_from_classes) {
4077                cur_method_ref = cur_precedence->trait_method;
4078                if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len,
4079                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4080                    zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4081                }
4082                zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
4083
4084                /** Ensure that the prefered method is actually available. */
4085                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4086                                              cur_method_ref->mname_len);
4087                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4088                                                 lcname,
4089                                                 cur_method_ref->mname_len + 1);
4090                efree(lcname);
4091                if (!method_exists) {
4092                    zend_error(E_COMPILE_ERROR,
4093                               "A precedence rule was defined for %s::%s but this method does not exist",
4094                               cur_method_ref->ce->name,
4095                               cur_method_ref->method_name);
4096                }
4097
4098                /** With the other traits, we are more permissive.
4099                    We do not give errors for those. This allows to be more
4100                    defensive in such definitions.
4101                    However, we want to make sure that the insteadof declaration
4102                    is consistent in itself.
4103                 */
4104                j = 0;
4105                while (cur_precedence->exclude_from_classes[j]) {
4106                    char* class_name = (char*)cur_precedence->exclude_from_classes[j];
4107                    zend_uint name_length = strlen(class_name);
4108
4109                    if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4110                        zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
4111                    }
4112                    zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
4113
4114                    /* make sure that the trait method is not from a class mentioned in
4115                     exclude_from_classes, for consistency */
4116                    if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
4117                        zend_error(E_COMPILE_ERROR,
4118                                   "Inconsistent insteadof definition. "
4119                                   "The method %s is to be used from %s, but %s is also on the exclude list",
4120                                   cur_method_ref->method_name,
4121                                   cur_precedence->trait_method->ce->name,
4122                                   cur_precedence->trait_method->ce->name);
4123                    }
4124
4125                    efree(class_name);
4126                    j++;
4127                }
4128            }
4129            i++;
4130        }
4131    }
4132
4133    if (ce->trait_aliases) {
4134        i = 0;
4135        while (ce->trait_aliases[i]) {
4136            /** For all aliases with an explicit class name, resolve the class now. */
4137            if (ce->trait_aliases[i]->trait_method->class_name) {
4138                cur_method_ref = ce->trait_aliases[i]->trait_method;
4139                if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4140                    zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4141                }
4142                zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
4143
4144                /** And, ensure that the referenced method is resolvable, too. */
4145                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4146                        cur_method_ref->mname_len);
4147                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4148                        lcname, cur_method_ref->mname_len + 1);
4149                efree(lcname);
4150
4151                if (!method_exists) {
4152                    zend_error(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name, cur_method_ref->method_name);
4153                }
4154            }
4155            i++;
4156        }
4157    }
4158}
4159/* }}} */
4160
4161static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
4162{
4163    size_t i = 0, j;
4164
4165    if (!precedences) {
4166        return;
4167    }
4168    while (precedences[i]) {
4169        if (precedences[i]->exclude_from_classes) {
4170            j = 0;
4171            while (precedences[i]->exclude_from_classes[j]) {
4172                if (precedences[i]->exclude_from_classes[j] == trait) {
4173                    zend_uint lcname_len = precedences[i]->trait_method->mname_len;
4174                    char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len);
4175
4176                    if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) {
4177                        efree(lcname);
4178                        zend_error(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name, trait->name);
4179                    }
4180                    efree(lcname);
4181                }
4182                ++j;
4183            }
4184        }
4185        ++i;
4186    }
4187}
4188/* }}} */
4189
4190static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4191{
4192    zend_uint i;
4193    HashTable *overriden = NULL;
4194
4195    for (i = 0; i < ce->num_traits; i++) {
4196        if (ce->trait_precedences) {
4197            HashTable exclude_table;
4198
4199            /* TODO: revisit this start size, may be its not optimal */
4200            zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
4201
4202            zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
4203
4204            /* copies functions, applies defined aliasing, and excludes unused trait methods */
4205            zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table);
4206
4207            zend_hash_destroy(&exclude_table);
4208        } else {
4209            zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
4210        }
4211    }
4212
4213    zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
4214
4215    if (overriden) {
4216        zend_hash_destroy(overriden);
4217        FREE_HASHTABLE(overriden);
4218    }
4219}
4220/* }}} */
4221
4222static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */
4223{
4224    size_t i;
4225
4226    if (coliding_ce == ce) {
4227        for (i = 0; i < current_trait; i++) {
4228            if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
4229                return ce->traits[i];
4230            }
4231        }
4232    }
4233
4234    return coliding_ce;
4235}
4236/* }}} */
4237
4238static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4239{
4240    size_t i;
4241    zend_property_info *property_info;
4242    zend_property_info *coliding_prop;
4243    zval compare_result;
4244    const char* prop_name;
4245    int   prop_name_length;
4246    ulong prop_hash;
4247    const char* class_name_unused;
4248    zend_bool not_compatible;
4249    zval* prop_value;
4250    char* doc_comment;
4251    zend_uint flags;
4252
4253    /* In the following steps the properties are inserted into the property table
4254     * for that, a very strict approach is applied:
4255     * - check for compatibility, if not compatible with any property in class -> fatal
4256     * - if compatible, then strict notice
4257     */
4258    for (i = 0; i < ce->num_traits; i++) {
4259        for (zend_hash_internal_pointer_reset(&ce->traits[i]->properties_info);
4260             zend_hash_get_current_data(&ce->traits[i]->properties_info, (void *) &property_info) == SUCCESS;
4261             zend_hash_move_forward(&ce->traits[i]->properties_info)) {
4262            /* first get the unmangeld name if necessary,
4263             * then check whether the property is already there
4264             */
4265            flags = property_info->flags;
4266            if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
4267                prop_hash = property_info->h;
4268                prop_name = property_info->name;
4269                prop_name_length = property_info->name_length;
4270            } else {
4271                /* for private and protected we need to unmangle the names */
4272                zend_unmangle_property_name_ex(property_info->name, property_info->name_length,
4273                                            &class_name_unused, &prop_name, &prop_name_length);
4274                prop_hash = zend_get_hash_value(prop_name, prop_name_length + 1);
4275            }
4276
4277            /* next: check for conflicts with current class */
4278            if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
4279                if (coliding_prop->flags & ZEND_ACC_SHADOW) {
4280                    zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
4281                    flags |= ZEND_ACC_CHANGED;
4282                } else {
4283                    if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
4284                        == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
4285                        /* flags are identical, now the value needs to be checked */
4286                        if (flags & ZEND_ACC_STATIC) {
4287                            not_compatible = (FAILURE == compare_function(&compare_result,
4288                                              ce->default_static_members_table[coliding_prop->offset],
4289                                              ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
4290                                  || (Z_LVAL(compare_result) != 0);
4291                        } else {
4292                            not_compatible = (FAILURE == compare_function(&compare_result,
4293                                              ce->default_properties_table[coliding_prop->offset],
4294                                              ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
4295                                  || (Z_LVAL(compare_result) != 0);
4296                        }
4297                    } else {
4298                        /* the flags are not identical, thus, we assume properties are not compatible */
4299                        not_compatible = 1;
4300                    }
4301
4302                    if (not_compatible) {
4303                        zend_error(E_COMPILE_ERROR,
4304                               "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
4305                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4306                                property_info->ce->name,
4307                                prop_name,
4308                                ce->name);
4309                    } else {
4310                        zend_error(E_STRICT,
4311                               "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
4312                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4313                                property_info->ce->name,
4314                                prop_name,
4315                                ce->name);
4316                        continue;
4317                    }
4318                }
4319            }
4320
4321            /* property not found, so lets add it */
4322            if (flags & ZEND_ACC_STATIC) {
4323                prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
4324            } else {
4325                prop_value = ce->traits[i]->default_properties_table[property_info->offset];
4326            }
4327            Z_ADDREF_P(prop_value);
4328
4329            doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
4330            zend_declare_property_ex(ce, prop_name, prop_name_length,
4331                                     prop_value, flags,
4332                                     doc_comment, property_info->doc_comment_len TSRMLS_CC);
4333        }
4334    }
4335}
4336/* }}} */
4337
4338static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4339{
4340    int i = 0;
4341    zend_trait_alias* cur_alias;
4342    char* lc_method_name;
4343
4344    if (ce->trait_aliases) {
4345        while (ce->trait_aliases[i]) {
4346            cur_alias = ce->trait_aliases[i];
4347            /** The trait for this alias has not been resolved, this means, this
4348                alias was not applied. Abort with an error. */
4349            if (!cur_alias->trait_method->ce) {
4350                if (cur_alias->alias) {
4351                    /** Plain old inconsistency/typo/bug */
4352                    zend_error(E_COMPILE_ERROR,
4353                               "An alias (%s) was defined for method %s(), but this method does not exist",
4354                               cur_alias->alias,
4355                               cur_alias->trait_method->method_name);
4356                } else {
4357                    /** Here are two possible cases:
4358                        1) this is an attempt to modifiy the visibility
4359                           of a method introduce as part of another alias.
4360                           Since that seems to violate the DRY principle,
4361                           we check against it and abort.
4362                        2) it is just a plain old inconsitency/typo/bug
4363                           as in the case where alias is set. */
4364
4365                    lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name,
4366                                                          cur_alias->trait_method->mname_len);
4367                    if (zend_hash_exists(&ce->function_table,
4368                                         lc_method_name,
4369                                         cur_alias->trait_method->mname_len+1)) {
4370                        efree(lc_method_name);
4371                        zend_error(E_COMPILE_ERROR,
4372                                   "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
4373                                   cur_alias->trait_method->method_name);
4374                    } else {
4375                        efree(lc_method_name);
4376                        zend_error(E_COMPILE_ERROR,
4377                                   "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
4378                                   cur_alias->trait_method->method_name);
4379
4380                    }
4381                }
4382            }
4383            i++;
4384        }
4385    }
4386}
4387/* }}} */
4388
4389ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4390{
4391
4392    if (ce->num_traits <= 0) {
4393        return;
4394    }
4395
4396    /* complete initialization of trait strutures in ce */
4397    zend_traits_init_trait_structures(ce TSRMLS_CC);
4398
4399    /* first care about all methods to be flattened into the class */
4400    zend_do_traits_method_binding(ce TSRMLS_CC);
4401
4402    /* Aliases which have not been applied indicate typos/bugs. */
4403    zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
4404
4405    /* then flatten the properties into it, to, mostly to notfiy developer about problems */
4406    zend_do_traits_property_binding(ce TSRMLS_CC);
4407
4408    /* verify that all abstract methods from traits have been implemented */
4409    zend_verify_abstract_class(ce TSRMLS_CC);
4410
4411    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
4412    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
4413        ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
4414    }
4415}
4416/* }}} */
4417
4418ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */
4419{
4420    zend_function *function;
4421    zval *op1, *op2;
4422
4423    if (compile_time) {
4424        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4425        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4426    } else {
4427        op1 = opline->op1.zv;
4428        op2 = opline->op2.zv;
4429    }
4430
4431    zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function);
4432    if (zend_hash_quick_add(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), function, sizeof(zend_function), NULL)==FAILURE) {
4433        int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
4434        zend_function *old_function;
4435
4436        if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), (void *) &old_function)==SUCCESS
4437            && old_function->type == ZEND_USER_FUNCTION
4438            && old_function->op_array.last > 0) {
4439            zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
4440                        function->common.function_name,
4441                        old_function->op_array.filename,
4442                        old_function->op_array.opcodes[0].lineno);
4443        } else {
4444            zend_error(error_level, "Cannot redeclare %s()", function->common.function_name);
4445        }
4446        return FAILURE;
4447    } else {
4448        (*function->op_array.refcount)++;
4449        function->op_array.static_variables = NULL; /* NULL out the unbound function */
4450        return SUCCESS;
4451    }
4452}
4453/* }}} */
4454
4455void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
4456{
4457    zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
4458    method_ref->ce = NULL;
4459
4460    /* REM: There should not be a need for copying,
4461       zend_do_begin_class_declaration is also just using that string */
4462    if (class_name) {
4463        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
4464        method_ref->class_name = Z_STRVAL(class_name->u.constant);
4465        method_ref->cname_len  = Z_STRLEN(class_name->u.constant);
4466    } else {
4467        method_ref->class_name = NULL;
4468        method_ref->cname_len  = 0;
4469    }
4470
4471    method_ref->method_name = Z_STRVAL(method_name->u.constant);
4472    method_ref->mname_len   = Z_STRLEN(method_name->u.constant);
4473
4474    result->u.op.ptr = method_ref;
4475    result->op_type = IS_TMP_VAR;
4476}
4477/* }}} */
4478
4479void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
4480{
4481    zend_class_entry *ce = CG(active_class_entry);
4482    zend_trait_alias *trait_alias;
4483
4484    if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
4485        zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
4486        return;
4487    } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) {
4488        zend_error(E_COMPILE_ERROR, "Cannot use 'abstract' as method modifier");
4489        return;
4490    } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) {
4491        zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier");
4492        return;
4493    }
4494
4495    trait_alias = emalloc(sizeof(zend_trait_alias));
4496    trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4497    trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
4498    if (alias) {
4499        trait_alias->alias = Z_STRVAL(alias->u.constant);
4500        trait_alias->alias_len = Z_STRLEN(alias->u.constant);
4501    } else {
4502        trait_alias->alias = NULL;
4503    }
4504    zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
4505}
4506/* }}} */
4507
4508void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
4509{
4510    zend_class_entry *ce = CG(active_class_entry);
4511    zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
4512
4513    trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4514    trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.op.ptr;
4515
4516    zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
4517}
4518/* }}} */
4519
4520ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
4521{
4522    zend_class_entry *ce, **pce;
4523    zval *op1, *op2;
4524
4525    if (compile_time) {
4526        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4527        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4528    } else {
4529        op1 = opline->op1.zv;
4530        op2 = opline->op2.zv;
4531    }
4532    if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) {
4533        zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
4534        return NULL;
4535    } else {
4536        ce = *pce;
4537    }
4538    ce->refcount++;
4539    if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
4540        ce->refcount--;
4541        if (!compile_time) {
4542            /* If we're in compile time, in practice, it's quite possible
4543             * that we'll never reach this class declaration at runtime,
4544             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
4545             * approach to work.
4546             */
4547            zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4548        }
4549        return NULL;
4550    } else {
4551        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
4552            zend_verify_abstract_class(ce TSRMLS_CC);
4553        }
4554        return ce;
4555    }
4556}
4557/* }}} */
4558
4559ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */
4560{
4561    zend_class_entry *ce, **pce;
4562    int found_ce;
4563    zval *op1, *op2;
4564
4565    if (compile_time) {
4566        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4567        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4568    } else {
4569        op1 = opline->op1.zv;
4570        op2 = opline->op2.zv;
4571    }
4572
4573    found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce);
4574
4575    if (found_ce == FAILURE) {
4576        if (!compile_time) {
4577            /* If we're in compile time, in practice, it's quite possible
4578             * that we'll never reach this class declaration at runtime,
4579             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
4580             * approach to work.
4581             */
4582            zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
4583        }
4584        return NULL;
4585    } else {
4586        ce = *pce;
4587    }
4588
4589    if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
4590        zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name);
4591    } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
4592        zend_error(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name, parent_ce->name);
4593    }
4594
4595    zend_do_inheritance(ce, parent_ce TSRMLS_CC);
4596
4597    ce->refcount++;
4598
4599    /* Register the derived class */
4600    if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), pce, sizeof(zend_class_entry *), NULL)==FAILURE) {
4601        zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4602    }
4603    return ce;
4604}
4605/* }}} */
4606
4607void zend_do_early_binding(TSRMLS_D) /* {{{ */
4608{
4609    zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
4610    HashTable *table;
4611
4612    while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
4613        opline--;
4614    }
4615
4616    switch (opline->opcode) {
4617        case ZEND_DECLARE_FUNCTION:
4618            if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1) == FAILURE) {
4619                return;
4620            }
4621            table = CG(function_table);
4622            break;
4623        case ZEND_DECLARE_CLASS:
4624            if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
4625                return;
4626            }
4627            table = CG(class_table);
4628            break;
4629        case ZEND_DECLARE_INHERITED_CLASS:
4630            {
4631                zend_op *fetch_class_opline = opline-1;
4632                zval *parent_name;
4633                zend_class_entry **pce;
4634
4635                parent_name = &CONSTANT(fetch_class_opline->op2.constant);
4636                if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) ||
4637                    ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
4638                     ((*pce)->type == ZEND_INTERNAL_CLASS))) {
4639                    if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) {
4640                        zend_uint *opline_num = &CG(active_op_array)->early_binding;
4641
4642                        while (*opline_num != -1) {
4643                            opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num;
4644                        }
4645                        *opline_num = opline - CG(active_op_array)->opcodes;
4646                        opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
4647                        opline->result_type = IS_UNUSED;
4648                        opline->result.opline_num = -1;
4649                    }
4650                    return;
4651                }
4652                if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) {
4653                    return;
4654                }
4655                /* clear unnecessary ZEND_FETCH_CLASS opcode */
4656                zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
4657                MAKE_NOP(fetch_class_opline);
4658
4659                table = CG(class_table);
4660                break;
4661            }
4662        case ZEND_VERIFY_ABSTRACT_CLASS:
4663        case ZEND_ADD_INTERFACE:
4664        case ZEND_ADD_TRAIT:
4665        case ZEND_BIND_TRAITS:
4666            /* We currently don't early-bind classes that implement interfaces */
4667            /* Classes with traits are handled exactly the same, no early-bind here */
4668            return;
4669        default:
4670            zend_error(E_COMPILE_ERROR, "Invalid binding type");
4671            return;
4672    }
4673
4674    zend_hash_quick_del(table, Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)), Z_HASH_P(&CONSTANT(opline->op1.constant)));
4675    zend_del_literal(CG(active_op_array), opline->op1.constant);
4676    zend_del_literal(CG(active_op_array), opline->op2.constant);
4677    MAKE_NOP(opline);
4678}
4679/* }}} */
4680
4681ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */
4682{
4683    if (op_array->early_binding != -1) {
4684        zend_bool orig_in_compilation = CG(in_compilation);
4685        zend_uint opline_num = op_array->early_binding;
4686        zend_class_entry **pce;
4687
4688        CG(in_compilation) = 1;
4689        while (opline_num != -1) {
4690            if (zend_lookup_class(Z_STRVAL_P(op_array->opcodes[opline_num-1].op2.zv), Z_STRLEN_P(op_array->opcodes[opline_num-1].op2.zv), &pce TSRMLS_CC) == SUCCESS) {
4691                do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), *pce, 0 TSRMLS_CC);
4692            }
4693            opline_num = op_array->opcodes[opline_num].result.opline_num;
4694        }
4695        CG(in_compilation) = orig_in_compilation;
4696    }
4697}
4698/* }}} */
4699
4700void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC) /* {{{ */
4701{
4702    int next_op_number = get_next_op_number(CG(active_op_array));
4703    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4704
4705    opline->opcode =