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   |          Nikita Popov <nikic@php.net>                                |
18   +----------------------------------------------------------------------+
19*/
20
21/* $Id$ */
22
23#include <zend_language_parser.h>
24#include "zend.h"
25#include "zend_compile.h"
26#include "zend_constants.h"
27#include "zend_llist.h"
28#include "zend_API.h"
29#include "zend_exceptions.h"
30#include "zend_virtual_cwd.h"
31#include "zend_multibyte.h"
32#include "zend_language_scanner.h"
33
34#define CONSTANT_EX(op_array, op) \
35    (op_array)->literals[op]
36
37#define CONSTANT(op) \
38    CONSTANT_EX(CG(active_op_array), op)
39
40#define SET_NODE(target, src) do { \
41        target ## _type = (src)->op_type; \
42        if ((src)->op_type == IS_CONST) { \
43            target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); \
44        } else { \
45            target = (src)->u.op; \
46        } \
47    } while (0)
48
49#define GET_NODE(target, src) do { \
50        (target)->op_type = src ## _type; \
51        if ((target)->op_type == IS_CONST) { \
52            (target)->u.constant = CONSTANT(src.constant); \
53        } else { \
54            (target)->u.op = src; \
55        } \
56    } while (0)
57
58static inline void zend_alloc_cache_slot(uint32_t literal TSRMLS_DC) {
59    zend_op_array *op_array = CG(active_op_array);
60    Z_CACHE_SLOT(op_array->literals[literal]) = op_array->last_cache_slot++;
61}
62
63#define POLYMORPHIC_CACHE_SLOT_SIZE 2
64
65static inline void zend_alloc_polymorphic_cache_slot(uint32_t literal TSRMLS_DC) {
66    zend_op_array *op_array = CG(active_op_array);
67    Z_CACHE_SLOT(op_array->literals[literal]) = op_array->last_cache_slot;
68    op_array->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE;
69}
70
71ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
72ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
73
74#ifndef ZTS
75ZEND_API zend_compiler_globals compiler_globals;
76ZEND_API zend_executor_globals executor_globals;
77#endif
78
79static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info TSRMLS_DC) /* {{{ */
80{
81    zend_property_info* new_property_info;
82
83    new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
84    memcpy(new_property_info, property_info, sizeof(zend_property_info));
85    zend_string_addref(new_property_info->name);
86    if (new_property_info->doc_comment) {
87        zend_string_addref(new_property_info->doc_comment);
88    }
89    return new_property_info;
90}
91/* }}} */
92
93static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
94{
95    zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
96    memcpy(new_property_info, property_info, sizeof(zend_property_info));
97    zend_string_addref(new_property_info->name);
98    return new_property_info;
99}
100/* }}} */
101
102static void zend_destroy_property_info(zval *zv) /* {{{ */
103{
104    zend_property_info *property_info = Z_PTR_P(zv);
105
106    zend_string_release(property_info->name);
107    if (property_info->doc_comment) {
108        zend_string_release(property_info->doc_comment);
109    }
110}
111/* }}} */
112
113static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
114{
115    zend_property_info *property_info = Z_PTR_P(zv);
116
117    zend_string_release(property_info->name);
118    free(property_info);
119}
120/* }}} */
121
122static zend_string *zend_new_interned_string_safe(zend_string *str TSRMLS_DC) /* {{{ */ {
123    zend_string *interned_str;
124
125    zend_string_addref(str);
126    interned_str = zend_new_interned_string(str TSRMLS_CC);
127    if (str != interned_str) {
128        return interned_str;
129    } else {
130        zend_string_release(str);
131        return str;
132    }
133}
134/* }}} */
135
136static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigned char *lex_pos TSRMLS_DC) /* {{{ */
137{
138    zend_string *result;
139    char char_pos_buf[32];
140    size_t char_pos_len = zend_sprintf(char_pos_buf, "%p", lex_pos);
141
142    const char *filename;
143    if (CG(active_op_array)->filename) {
144        filename = CG(active_op_array)->filename->val;
145    } else {
146        filename = "-";
147    }
148
149    /* NULL, name length, filename length, last accepting char position length */
150    result = zend_string_alloc(1 + name->len + strlen(filename) + char_pos_len, 0);
151
152    result->val[0] = '\0';
153    sprintf(result->val + 1, "%s%s%s", name->val, filename, char_pos_buf);
154    return result;
155}
156/* }}} */
157
158static void init_compiler_declarables(TSRMLS_D) /* {{{ */
159{
160    ZVAL_LONG(&CG(declarables).ticks, 0);
161}
162/* }}} */
163
164void zend_init_compiler_context(TSRMLS_D) /* {{{ */
165{
166    CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
167    CG(context).vars_size = 0;
168    CG(context).literals_size = 0;
169    CG(context).current_brk_cont = -1;
170    CG(context).backpatch_count = 0;
171    CG(context).in_finally = 0;
172    CG(context).labels = NULL;
173}
174/* }}} */
175
176void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
177{
178    zend_stack_init(&CG(loop_var_stack), sizeof(znode));
179    zend_stack_init(&CG(delayed_oplines_stack), sizeof(zend_op));
180    CG(active_class_entry) = NULL;
181    CG(in_compilation) = 0;
182    CG(start_lineno) = 0;
183    CG(current_namespace) = NULL;
184    CG(in_namespace) = 0;
185    CG(has_bracketed_namespaces) = 0;
186    CG(current_import) = NULL;
187    CG(current_import_function) = NULL;
188    CG(current_import_const) = NULL;
189    zend_hash_init(&CG(const_filenames), 8, NULL, NULL, 0);
190    init_compiler_declarables(TSRMLS_C);
191    zend_stack_init(&CG(context_stack), sizeof(CG(context)));
192
193    CG(encoding_declared) = 0;
194}
195/* }}} */
196
197ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */
198{
199    TSRMLS_FETCH();
200
201    zend_file_handle_dtor(fh TSRMLS_CC);
202}
203/* }}} */
204
205void init_compiler(TSRMLS_D) /* {{{ */
206{
207    CG(arena) = zend_arena_create(64 * 1024);
208    CG(active_op_array) = NULL;
209    memset(&CG(context), 0, sizeof(CG(context)));
210    zend_init_compiler_data_structures(TSRMLS_C);
211    zend_init_rsrc_list(TSRMLS_C);
212    zend_hash_init(&CG(filenames_table), 8, NULL, free_string_zval, 0);
213    zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0);
214    CG(unclean_shutdown) = 0;
215}
216/* }}} */
217
218void shutdown_compiler(TSRMLS_D) /* {{{ */
219{
220    zend_stack_destroy(&CG(loop_var_stack));
221    zend_stack_destroy(&CG(delayed_oplines_stack));
222    zend_hash_destroy(&CG(filenames_table));
223    zend_hash_destroy(&CG(const_filenames));
224    zend_stack_destroy(&CG(context_stack));
225    zend_arena_destroy(CG(arena));
226}
227/* }}} */
228
229ZEND_API zend_string *zend_set_compiled_filename(zend_string *new_compiled_filename TSRMLS_DC) /* {{{ */
230{
231    zend_string *p;
232
233    p = zend_hash_find_ptr(&CG(filenames_table), new_compiled_filename);
234    if (p != NULL) {
235        CG(compiled_filename) = p;
236        return p;
237    }
238    p = zend_string_copy(new_compiled_filename);
239    zend_hash_update_ptr(&CG(filenames_table), new_compiled_filename, p);
240    CG(compiled_filename) = p;
241    return p;
242}
243/* }}} */
244
245ZEND_API void zend_restore_compiled_filename(zend_string *original_compiled_filename TSRMLS_DC) /* {{{ */
246{
247    CG(compiled_filename) = original_compiled_filename;
248}
249/* }}} */
250
251ZEND_API zend_string *zend_get_compiled_filename(TSRMLS_D) /* {{{ */
252{
253    return CG(compiled_filename);
254}
255/* }}} */
256
257ZEND_API int zend_get_compiled_lineno(TSRMLS_D) /* {{{ */
258{
259    return CG(zend_lineno);
260}
261/* }}} */
262
263ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */
264{
265    return CG(in_compilation);
266}
267/* }}} */
268
269static uint32_t get_temporary_variable(zend_op_array *op_array) /* {{{ */
270{
271    return (uint32_t)op_array->T++;
272}
273/* }}} */
274
275static int lookup_cv(zend_op_array *op_array, zend_string* name TSRMLS_DC) /* {{{ */{
276    int i = 0;
277    zend_ulong hash_value = zend_string_hash_val(name);
278
279    while (i < op_array->last_var) {
280        if (op_array->vars[i]->val == name->val ||
281            (op_array->vars[i]->h == hash_value &&
282             op_array->vars[i]->len == name->len &&
283             memcmp(op_array->vars[i]->val, name->val, name->len) == 0)) {
284            zend_string_release(name);
285            return (int)(zend_intptr_t)EX_VAR_NUM_2(NULL, i);
286        }
287        i++;
288    }
289    i = op_array->last_var;
290    op_array->last_var++;
291    if (op_array->last_var > CG(context).vars_size) {
292        CG(context).vars_size += 16; /* FIXME */
293        op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*));
294    }
295
296    op_array->vars[i] = zend_new_interned_string(name TSRMLS_CC);
297    return (int)(zend_intptr_t)EX_VAR_NUM_2(NULL, i);
298}
299/* }}} */
300
301void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */
302{
303    zval_dtor(&CONSTANT_EX(op_array, n));
304    if (n + 1 == op_array->last_literal) {
305        op_array->last_literal--;
306    } else {
307        ZVAL_UNDEF(&CONSTANT_EX(op_array, n));
308    }
309}
310/* }}} */
311
312/* Common part of zend_add_literal and zend_append_individual_literal */
313static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int literal_position TSRMLS_DC) /* {{{ */
314{
315    if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) {
316        zend_string_hash_val(Z_STR_P(zv));
317        Z_STR_P(zv) = zend_new_interned_string(Z_STR_P(zv) TSRMLS_CC);
318        if (IS_INTERNED(Z_STR_P(zv))) {
319            Z_TYPE_FLAGS_P(zv) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
320        }
321    }
322    ZVAL_COPY_VALUE(&CONSTANT_EX(op_array, literal_position), zv);
323    Z_CACHE_SLOT(op_array->literals[literal_position]) = -1;
324}
325/* }}} */
326
327/* Is used while compiling a function, using the context to keep track
328   of an approximate size to avoid to relocate to often.
329   Literals are truncated to actual size in the second compiler pass (pass_two()). */
330int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
331{
332    int i = op_array->last_literal;
333    op_array->last_literal++;
334    if (i >= CG(context).literals_size) {
335        while (i >= CG(context).literals_size) {
336            CG(context).literals_size += 16; /* FIXME */
337        }
338        op_array->literals = (zval*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zval));
339    }
340    zend_insert_literal(op_array, zv, i TSRMLS_CC);
341    return i;
342}
343/* }}} */
344
345static int zend_add_func_name_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
346{
347    int ret;
348    zend_string *lc_name;
349    zval c;
350
351    if (op_array->last_literal > 0 &&
352        &op_array->literals[op_array->last_literal - 1] == zv &&
353        Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
354        /* we already have function name as last literal (do nothing) */
355        ret = op_array->last_literal - 1;
356    } else {
357        ret = zend_add_literal(op_array, zv TSRMLS_CC);
358    }
359
360    lc_name = zend_string_alloc(Z_STRLEN_P(zv), 0);
361    zend_str_tolower_copy(lc_name->val, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
362    ZVAL_NEW_STR(&c, lc_name);
363    zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
364
365    return ret;
366}
367/* }}} */
368
369static int zend_add_ns_func_name_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
370{
371    int ret;
372    zend_string *lc_name;
373    const char *ns_separator;
374    int lc_len;
375    zval c;
376
377    if (op_array->last_literal > 0 &&
378        &op_array->literals[op_array->last_literal - 1] == zv &&
379        Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
380        /* we already have function name as last literal (do nothing) */
381        ret = op_array->last_literal - 1;
382    } else {
383        ret = zend_add_literal(op_array, zv TSRMLS_CC);
384    }
385
386    lc_name = zend_string_alloc(Z_STRLEN_P(zv), 0);
387    zend_str_tolower_copy(lc_name->val, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
388    ZVAL_NEW_STR(&c, lc_name);
389    zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
390
391    ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv));
392
393    if (ns_separator != NULL) {
394        ns_separator += 1;
395        lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv));
396        lc_name = zend_string_alloc(lc_len, 0);
397        zend_str_tolower_copy(lc_name->val, ns_separator, lc_len);
398        ZVAL_NEW_STR(&c, lc_name);
399        zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
400    }
401
402    return ret;
403}
404/* }}} */
405
406static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ {
407    int ret;
408    zend_string *lc_name;
409
410    zval zv;
411    ZVAL_STR(&zv, name);
412
413    ret = zend_add_literal(op_array, &zv TSRMLS_CC);
414    name = Z_STR(zv); /* Load new name string in case it was interned */
415
416    lc_name = zend_string_alloc(name->len, 0);
417    zend_str_tolower_copy(lc_name->val, name->val, name->len);
418
419    ZVAL_NEW_STR(&zv, lc_name);
420    zend_add_literal(CG(active_op_array), &zv TSRMLS_CC);
421
422    zend_alloc_cache_slot(ret TSRMLS_CC);
423
424    return ret;
425}
426/* }}} */
427
428static int zend_add_const_name_literal(zend_op_array *op_array, zval *zv, int unqualified TSRMLS_DC) /* {{{ */
429{
430    int ret;
431    char *name;
432    zend_string *tmp_name;
433    const char *ns_separator;
434    int name_len, ns_len;
435    zval c;
436
437    if (op_array->last_literal > 0 &&
438        &op_array->literals[op_array->last_literal - 1] == zv &&
439        Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
440        /* we already have function name as last literal (do nothing) */
441        ret = op_array->last_literal - 1;
442    } else {
443        ret = zend_add_literal(op_array, zv TSRMLS_CC);
444    }
445
446    /* skip leading '\\' */
447    if (Z_STRVAL_P(zv)[0] == '\\') {
448        name_len = Z_STRLEN_P(zv) - 1;
449        name = Z_STRVAL_P(zv) + 1;
450    } else {
451        name_len = Z_STRLEN_P(zv);
452        name = Z_STRVAL_P(zv);
453    }
454    ns_separator = zend_memrchr(name, '\\', name_len);
455    if (ns_separator) {
456        ns_len = ns_separator - name;
457    } else {
458        ns_len = 0;
459    }
460
461    if (ns_len) {
462        /* lowercased namespace name & original constant name */
463        tmp_name = zend_string_init(name, name_len, 0);
464        zend_str_tolower(tmp_name->val, ns_len);
465        ZVAL_NEW_STR(&c, tmp_name);
466        zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
467
468        /* lowercased namespace name & lowercased constant name */
469        tmp_name = zend_string_alloc(name_len, 0);
470        zend_str_tolower_copy(tmp_name->val, name, name_len);
471        ZVAL_NEW_STR(&c, tmp_name);
472        zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
473    }
474
475    if (ns_len) {
476        if (!unqualified) {
477            return ret;
478        }
479        ns_len++;
480        name += ns_len;
481        name_len -= ns_len;
482    }
483
484    /* original constant name */
485    tmp_name = zend_string_init(name, name_len, 0);
486    ZVAL_NEW_STR(&c, tmp_name);
487    zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
488
489    /* lowercased constant name */
490    tmp_name = zend_string_alloc(name_len, 0);
491    zend_str_tolower_copy(tmp_name->val, name, name_len);
492    ZVAL_NEW_STR(&c, tmp_name);
493    zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
494
495    return ret;
496}
497/* }}} */
498
499#define LITERAL_STR(op, str) do { \
500        zval _c; \
501        ZVAL_STR(&_c, str); \
502        op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
503    } while (0)
504
505#define MAKE_NOP(opline) do { \
506    opline->opcode = ZEND_NOP; \
507    memset(&opline->result, 0, sizeof(opline->result)); \
508    memset(&opline->op1, 0, sizeof(opline->op1)); \
509    memset(&opline->op2, 0, sizeof(opline->op2)); \
510    opline->result_type = opline->op1_type = opline->op2_type = IS_UNUSED; \
511} while (0)
512
513void zend_stop_lexing(TSRMLS_D) {
514    LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
515}
516
517static inline void zend_begin_loop(TSRMLS_D) /* {{{ */
518{
519    zend_brk_cont_element *brk_cont_element;
520    int parent;
521
522    parent = CG(context).current_brk_cont;
523    CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont;
524    brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
525    brk_cont_element->start = get_next_op_number(CG(active_op_array));
526    brk_cont_element->parent = parent;
527}
528/* }}} */
529
530static inline void zend_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */
531{
532    if (!has_loop_var) {
533        /* The start fileld is used to free temporary variables in case of exceptions.
534         * We won't try to free something of we don't have loop variable.
535         */
536        CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1;
537    }
538    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr;
539    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array));
540    CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent;
541}
542/* }}} */
543
544void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
545{
546    if (op1->op_type==IS_TMP_VAR) {
547        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
548
549        opline->opcode = ZEND_FREE;
550        SET_NODE(opline->op1, op1);
551        SET_UNUSED(opline->op2);
552    } else if (op1->op_type==IS_VAR) {
553        zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
554
555        while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) {
556            opline--;
557        }
558        if (opline->result_type == IS_VAR
559            && opline->result.var == op1->u.op.var) {
560            if (opline->opcode == ZEND_FETCH_R ||
561                opline->opcode == ZEND_FETCH_DIM_R ||
562                opline->opcode == ZEND_FETCH_OBJ_R ||
563                opline->opcode == ZEND_QM_ASSIGN_VAR) {
564                /* It's very rare and useless case. It's better to use
565                   additional FREE opcode and simplify the FETCH handlers
566                   their selves */
567                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
568                opline->opcode = ZEND_FREE;
569                SET_NODE(opline->op1, op1);
570                SET_UNUSED(opline->op2);
571            } else {
572                opline->result_type |= EXT_TYPE_UNUSED;
573            }
574        } else {
575            while (opline>CG(active_op_array)->opcodes) {
576                if (opline->opcode == ZEND_FETCH_DIM_R
577                    && opline->op1_type == IS_VAR
578                    && opline->op1.var == op1->u.op.var) {
579                    /* This should the end of a list() construct
580                     * Mark its result as unused
581                     */
582                    opline->extended_value = ZEND_FETCH_STANDARD;
583                    break;
584                } else if (opline->result_type==IS_VAR
585                    && opline->result.var == op1->u.op.var) {
586                    if (opline->opcode == ZEND_NEW) {
587                        opline->result_type |= EXT_TYPE_UNUSED;
588                        opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
589                        while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) {
590                            opline--;
591                        }
592                        opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED;
593                    }
594                    break;
595                }
596                opline--;
597            }
598        }
599    } else if (op1->op_type == IS_CONST) {
600        /* Destroy value without using GC: When opcache moves arrays into SHM it will
601         * free the zend_array structure, so references to it from outside the op array
602         * become invalid. GC would cause such a reference in the root buffer. */
603        zval *zv = &op1->u.constant;
604        if (Z_REFCOUNTED_P(zv) && !Z_DELREF_P(zv)) {
605            _zval_dtor_func_for_ptr(Z_COUNTED_P(zv) ZEND_FILE_LINE_CC);
606        }
607    }
608}
609/* }}} */
610
611uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
612{
613    uint32_t new_flags = flags | new_flag;
614    if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
615        zend_error_noreturn(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
616    }
617    if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
618        zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
619    }
620    if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
621        zend_error_noreturn(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
622    }
623    if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
624        zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
625    }
626    if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
627        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
628    }
629    return new_flags;
630}
631/* }}} */
632
633zend_string *zend_concat3(char *str1, size_t str1_len, char *str2, size_t str2_len, char *str3, size_t str3_len) /* {{{ */
634{
635    size_t len = str1_len + str2_len + str3_len;
636    zend_string *res = zend_string_alloc(len, 0);
637
638    memcpy(res->val, str1, str1_len);
639    memcpy(res->val + str1_len, str2, str2_len);
640    memcpy(res->val + str1_len + str2_len, str3, str3_len);
641    res->val[len] = '\0';
642
643    return res;
644}
645
646zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2, size_t name2_len) {
647    return zend_concat3(name1, name1_len, "\\", 1, name2, name2_len);
648}
649
650zend_string *zend_prefix_with_ns(zend_string *name TSRMLS_DC) {
651    if (CG(current_namespace)) {
652        zend_string *ns = CG(current_namespace);
653        return zend_concat_names(ns->val, ns->len, name->val, name->len);
654    } else {
655        return zend_string_copy(name);
656    }
657}
658
659void *zend_hash_find_ptr_lc(HashTable *ht, char *str, size_t len) {
660    void *result;
661    zend_string *lcname = zend_string_alloc(len, 0);
662    zend_str_tolower_copy(lcname->val, str, len);
663    result = zend_hash_find_ptr(ht, lcname);
664    zend_string_free(lcname);
665    return result;
666}
667
668zend_string *zend_resolve_non_class_name(
669    zend_string *name, uint32_t type, zend_bool *is_fully_qualified,
670    zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC
671) {
672    char *compound;
673    *is_fully_qualified = 0;
674
675    if (name->val[0] == '\\') {
676        /* Remove \ prefix (only relevant if this is a string rather than a label) */
677        return zend_string_init(name->val + 1, name->len - 1, 0);
678    }
679
680    if (type == ZEND_NAME_FQ) {
681        *is_fully_qualified = 1;
682        return zend_string_copy(name);
683    }
684
685    if (type == ZEND_NAME_RELATIVE) {
686        *is_fully_qualified = 1;
687        return zend_prefix_with_ns(name TSRMLS_CC);
688    }
689
690    if (current_import_sub) {
691        /* If an unqualified name is a function/const alias, replace it. */
692        zend_string *import_name;
693        if (case_sensitive) {
694            import_name = zend_hash_find_ptr(current_import_sub, name);
695        } else {
696            import_name = zend_hash_find_ptr_lc(current_import_sub, name->val, name->len);
697        }
698
699        if (import_name) {
700            *is_fully_qualified = 1;
701            return zend_string_copy(import_name);
702        }
703    }
704
705    compound = memchr(name->val, '\\', name->len);
706    if (compound) {
707        *is_fully_qualified = 1;
708    }
709
710    if (compound && CG(current_import)) {
711        /* If the first part of a qualified name is an alias, substitute it. */
712        size_t len = compound - name->val;
713        zend_string *import_name = zend_hash_find_ptr_lc(CG(current_import), name->val, len);
714
715        if (import_name) {
716            return zend_concat_names(
717                import_name->val, import_name->len, name->val + len + 1, name->len - len - 1);
718        }
719    }
720
721    return zend_prefix_with_ns(name TSRMLS_CC);
722}
723/* }}} */
724
725zend_string *zend_resolve_function_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified TSRMLS_DC) /* {{{ */
726{
727    return zend_resolve_non_class_name(
728        name, type, is_fully_qualified, 0, CG(current_import_function) TSRMLS_CC);
729}
730/* }}} */
731
732zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified TSRMLS_DC) /* {{{ */ {
733    return zend_resolve_non_class_name(
734        name, type, is_fully_qualified, 1, CG(current_import_const) TSRMLS_CC);
735}
736/* }}} */
737
738zend_string *zend_resolve_class_name(zend_string *name, uint32_t type TSRMLS_DC) /* {{{ */
739{
740    char *compound;
741
742    if (type == ZEND_NAME_RELATIVE) {
743        return zend_prefix_with_ns(name TSRMLS_CC);
744    }
745
746    if (type == ZEND_NAME_FQ || name->val[0] == '\\') {
747        /* Remove \ prefix (only relevant if this is a string rather than a label) */
748        if (name->val[0] == '\\') {
749            name = zend_string_init(name->val + 1, name->len - 1, 0);
750        } else {
751            zend_string_addref(name);
752        }
753        /* Ensure that \self, \parent and \static are not used */
754        if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
755            zend_error_noreturn(E_COMPILE_ERROR, "'\\%s' is an invalid class name", name->val);
756        }
757        return name;
758    }
759
760    if (CG(current_import)) {
761        compound = memchr(name->val, '\\', name->len);
762        if (compound) {
763            /* If the first part of a qualified name is an alias, substitute it. */
764            size_t len = compound - name->val;
765            zend_string *import_name = zend_hash_find_ptr_lc(CG(current_import), name->val, len);
766
767            if (import_name) {
768                return zend_concat_names(
769                    import_name->val, import_name->len, name->val + len + 1, name->len - len - 1);
770            }
771        } else {
772            /* If an unqualified name is an alias, replace it. */
773            zend_string *import_name
774                = zend_hash_find_ptr_lc(CG(current_import), name->val, name->len);
775
776            if (import_name) {
777                return zend_string_copy(import_name);
778            }
779        }
780    }
781
782    /* If not fully qualified and not an alias, prepend the current namespace */
783    return zend_prefix_with_ns(name TSRMLS_CC);
784}
785/* }}} */
786
787zend_string *zend_resolve_class_name_ast(zend_ast *ast TSRMLS_DC) /* {{{ */
788{
789    zend_string *name = zend_ast_get_str(ast);
790    return zend_resolve_class_name(name, ast->attr TSRMLS_CC);
791}
792/* }}} */
793
794static void ptr_dtor(zval *zv) /* {{{ */
795{
796    efree(Z_PTR_P(zv));
797}
798/* }}} */
799
800static void str_dtor(zval *zv)  /* {{{ */ {
801    zend_string_release(Z_STR_P(zv));
802}
803/* }}} */
804
805void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */
806{
807    zend_label *dest;
808    zend_long current, distance;
809    zval *label;
810
811    if (pass2) {
812        label = opline->op2.zv;
813    } else {
814        label = &CONSTANT_EX(op_array, opline->op2.constant);
815    }
816    if (CG(context).labels == NULL ||
817        (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) {
818
819        if (pass2) {
820            CG(in_compilation) = 1;
821            CG(active_op_array) = op_array;
822            CG(zend_lineno) = opline->lineno;
823            zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
824        } else {
825            /* Label is not defined. Delay to pass 2. */
826            return;
827        }
828    }
829
830    opline->op1.opline_num = dest->opline_num;
831    zval_dtor(label);
832    ZVAL_NULL(label);
833
834    /* Check that we are not moving into loop or switch */
835    current = opline->extended_value;
836    for (distance = 0; current != dest->brk_cont; distance++) {
837        if (current == -1) {
838            if (pass2) {
839                CG(in_compilation) = 1;
840                CG(active_op_array) = op_array;
841                CG(zend_lineno) = opline->lineno;
842            }
843            zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
844        }
845        current = op_array->brk_cont_array[current].parent;
846    }
847
848    if (distance == 0) {
849        /* Nothing to break out of, optimize to ZEND_JMP */
850        opline->opcode = ZEND_JMP;
851        opline->extended_value = 0;
852        SET_UNUSED(opline->op2);
853    } else {
854        /* Set real break distance */
855        ZVAL_LONG(label, distance);
856    }
857}
858/* }}} */
859
860void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
861{
862    if (CG(context).labels) {
863        zend_hash_destroy(CG(context).labels);
864        FREE_HASHTABLE(CG(context).labels);
865        CG(context).labels = NULL;
866    }
867    if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
868        zend_compiler_context *ctx = zend_stack_top(&CG(context_stack));
869        CG(context) = *ctx;
870        zend_stack_del_top(&CG(context_stack));
871    }
872}
873/* }}} */
874
875static zend_bool zend_is_call(zend_ast *ast);
876
877static int generate_free_loop_var(znode *var TSRMLS_DC) /* {{{ */
878{
879    switch (var->op_type) {
880        case IS_UNUSED:
881            /* Stack separator on function boundary, stop applying */
882            return 1;
883        case IS_VAR:
884        case IS_TMP_VAR:
885        {
886            zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
887
888            opline->opcode = var->op_type == IS_TMP_VAR ? ZEND_FREE : ZEND_SWITCH_FREE;
889            SET_NODE(opline->op1, var);
890            SET_UNUSED(opline->op2);
891        }
892    }
893
894    return 0;
895}
896/* }}} */
897
898static uint32_t zend_add_try_element(uint32_t try_op TSRMLS_DC) /* {{{ */
899{
900    zend_op_array *op_array = CG(active_op_array);
901    uint32_t try_catch_offset = op_array->last_try_catch++;
902    zend_try_catch_element *elem;
903
904    op_array->try_catch_array = safe_erealloc(
905        op_array->try_catch_array, sizeof(zend_try_catch_element), op_array->last_try_catch, 0);
906
907    elem = &op_array->try_catch_array[try_catch_offset];
908    elem->try_op = try_op;
909    elem->catch_op = 0;
910    elem->finally_op = 0;
911    elem->finally_end = 0;
912
913    return try_catch_offset;
914}
915/* }}} */
916
917ZEND_API void function_add_ref(zend_function *function) /* {{{ */
918{
919    if (function->type == ZEND_USER_FUNCTION) {
920        zend_op_array *op_array = &function->op_array;
921
922        (*op_array->refcount)++;
923        if (op_array->static_variables) {
924            HashTable *static_variables = op_array->static_variables;
925
926            ALLOC_HASHTABLE(op_array->static_variables);
927            zend_array_dup(op_array->static_variables, static_variables);
928        }
929        op_array->run_time_cache = NULL;
930    } else if (function->type == ZEND_INTERNAL_FUNCTION) {
931        if (function->common.function_name) {
932            zend_string_addref(function->common.function_name);
933        }
934    }
935}
936/* }}} */
937
938static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) /* {{{ */
939{
940    zend_function *function, *new_function;
941
942    if (!ce->parent) {
943        return;
944    }
945
946    /* You cannot change create_object */
947    ce->create_object = ce->parent->create_object;
948
949    /* Inherit special functions if needed */
950    if (!ce->get_iterator) {
951        ce->get_iterator = ce->parent->get_iterator;
952    }
953    if (!ce->iterator_funcs.funcs) {
954        ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
955    }
956    if (!ce->__get) {
957        ce->__get   = ce->parent->__get;
958    }
959    if (!ce->__set) {
960        ce->__set = ce->parent->__set;
961    }
962    if (!ce->__unset) {
963        ce->__unset = ce->parent->__unset;
964    }
965    if (!ce->__isset) {
966        ce->__isset = ce->parent->__isset;
967    }
968    if (!ce->__call) {
969        ce->__call = ce->parent->__call;
970    }
971    if (!ce->__callstatic) {
972        ce->__callstatic = ce->parent->__callstatic;
973    }
974    if (!ce->__tostring) {
975        ce->__tostring = ce->parent->__tostring;
976    }
977    if (!ce->clone) {
978        ce->clone = ce->parent->clone;
979    }
980    if(!ce->serialize) {
981        ce->serialize = ce->parent->serialize;
982    }
983    if(!ce->unserialize) {
984        ce->unserialize = ce->parent->unserialize;
985    }
986    if (!ce->destructor) {
987        ce->destructor   = ce->parent->destructor;
988    }
989    if (!ce->__debugInfo) {
990        ce->__debugInfo = ce->parent->__debugInfo;
991    }
992    if (ce->constructor) {
993        if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
994            zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
995                ce->parent->name->val, ce->parent->constructor->common.function_name->val,
996                ce->name->val, ce->constructor->common.function_name->val
997                );
998        }
999        return;
1000    }
1001
1002    if ((function = zend_hash_str_find_ptr(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) != NULL) {
1003        /* inherit parent's constructor */
1004        if (function->type == ZEND_INTERNAL_FUNCTION) {
1005            new_function = pemalloc(sizeof(zend_internal_function), 1);
1006            memcpy(new_function, function, sizeof(zend_internal_function));
1007        } else {
1008            new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1009            memcpy(new_function, function, sizeof(zend_op_array));
1010        }
1011        zend_hash_str_update_ptr(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1, new_function);
1012        function_add_ref(new_function);
1013    } else {
1014        /* Don't inherit the old style constructor if we already have the new style constructor */
1015        zend_string *lc_class_name;
1016        zend_string *lc_parent_class_name;
1017
1018        lc_class_name = zend_string_alloc(ce->name->len, 0);
1019        zend_str_tolower_copy(lc_class_name->val, ce->name->val, ce->name->len);
1020        if (!zend_hash_exists(&ce->function_table, lc_class_name)) {
1021            lc_parent_class_name = zend_string_alloc(ce->parent->name->len, 0);
1022            zend_str_tolower_copy(lc_parent_class_name->val, ce->parent->name->val, ce->parent->name->len);
1023            if (!zend_hash_exists(&ce->function_table, lc_parent_class_name) &&
1024                    (function = zend_hash_find_ptr(&ce->parent->function_table, lc_parent_class_name)) != NULL) {
1025                if (function->common.fn_flags & ZEND_ACC_CTOR) {
1026                    /* inherit parent's constructor */
1027                    new_function = pemalloc(sizeof(zend_function), function->type == ZEND_INTERNAL_FUNCTION);
1028                    memcpy(new_function, function, sizeof(zend_function));
1029                    zend_hash_update_ptr(&ce->function_table, lc_parent_class_name, new_function);
1030                    function_add_ref(new_function);
1031                }
1032            }
1033            zend_string_release(lc_parent_class_name);
1034        }
1035        zend_string_free(lc_class_name);
1036    }
1037    ce->constructor = ce->parent->constructor;
1038}
1039/* }}} */
1040
1041char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
1042{
1043    if (fn_flags & ZEND_ACC_PRIVATE) {
1044        return "private";
1045    }
1046    if (fn_flags & ZEND_ACC_PROTECTED) {
1047        return "protected";
1048    }
1049    if (fn_flags & ZEND_ACC_PUBLIC) {
1050        return "public";
1051    }
1052    return "";
1053}
1054/* }}} */
1055
1056static zend_function *do_inherit_method(zend_function *old_function TSRMLS_DC) /* {{{ */
1057{
1058    zend_function *new_function;
1059
1060    if (old_function->type == ZEND_INTERNAL_FUNCTION) {
1061        new_function = pemalloc(sizeof(zend_internal_function), 1);
1062        memcpy(new_function, old_function, sizeof(zend_internal_function));
1063    } else {
1064        new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1065        memcpy(new_function, old_function, sizeof(zend_op_array));
1066    }
1067    /* The class entry of the derived function intentionally remains the same
1068     * as that of the parent class.  That allows us to know in which context
1069     * we're running, and handle private method calls properly.
1070     */
1071    function_add_ref(new_function);
1072    return new_function;
1073}
1074/* }}} */
1075
1076static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
1077{
1078    uint32_t i, num_args;
1079
1080    /* If it's a user function then arg_info == NULL means we don't have any parameters but
1081     * we still need to do the arg number checks.  We are only willing to ignore this for internal
1082     * functions because extensions don't always define arg_info.
1083     */
1084    if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
1085        return 1;
1086    }
1087
1088    /* Checks for constructors only if they are declared in an interface,
1089     * or explicitly marked as abstract
1090     */
1091    if ((fe->common.fn_flags & ZEND_ACC_CTOR)
1092        && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
1093            && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
1094        return 1;
1095    }
1096
1097    /* If both methods are private do not enforce a signature */
1098    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
1099        return 1;
1100    }
1101
1102    /* check number of arguments */
1103    if (proto->common.required_num_args < fe->common.required_num_args
1104        || proto->common.num_args > fe->common.num_args) {
1105        return 0;
1106    }
1107
1108    /* by-ref constraints on return values are covariant */
1109    if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1110        && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
1111        return 0;
1112    }
1113
1114    if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
1115        && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
1116        return 0;
1117    }
1118
1119    /* For variadic functions any additional (optional) arguments that were added must be
1120     * checked against the signature of the variadic argument, so in this case we have to
1121     * go through all the parameters of the function and not just those present in the
1122     * prototype. */
1123    num_args = proto->common.num_args;
1124    if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
1125        && fe->common.num_args > proto->common.num_args) {
1126        num_args = fe->common.num_args;
1127    }
1128
1129    for (i = 0; i < num_args; i++) {
1130        zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
1131
1132        zend_arg_info *proto_arg_info;
1133        if (i < proto->common.num_args) {
1134            proto_arg_info = &proto->common.arg_info[i];
1135        } else {
1136            proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
1137        }
1138
1139        if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
1140            /* Only one has a type hint and the other one doesn't */
1141            return 0;
1142        }
1143
1144        if (fe_arg_info->class_name) {
1145            zend_string *fe_class_name, *proto_class_name;
1146
1147            if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
1148                fe_class_name = zend_string_copy(proto->common.scope->name);
1149            } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
1150                fe_class_name = zend_string_copy(fe->common.scope->name);
1151            } else {
1152                fe_class_name = zend_string_init(
1153                    fe_arg_info->class_name,
1154                    fe_arg_info->class_name_len, 0);
1155            }
1156
1157            if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
1158                proto_class_name = zend_string_copy(proto->common.scope->parent->name);
1159            } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
1160                proto_class_name = zend_string_copy(proto->common.scope->name);
1161            } else {
1162                proto_class_name = zend_string_init(
1163                    proto_arg_info->class_name,
1164                    proto_arg_info->class_name_len, 0);
1165            }
1166
1167            if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
1168                const char *colon;
1169
1170                if (fe->common.type != ZEND_USER_FUNCTION) {
1171                    zend_string_release(proto_class_name);
1172                    zend_string_release(fe_class_name);
1173                    return 0;
1174                } else if (strchr(proto_class_name->val, '\\') != NULL ||
1175                        (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL ||
1176                        strcasecmp(colon+1, proto_class_name->val) != 0) {
1177                    zend_class_entry *fe_ce, *proto_ce;
1178
1179                    fe_ce = zend_lookup_class(fe_class_name TSRMLS_CC);
1180                    proto_ce = zend_lookup_class(proto_class_name TSRMLS_CC);
1181
1182                    /* Check for class alias */
1183                    if (!fe_ce || !proto_ce ||
1184                            fe_ce->type == ZEND_INTERNAL_CLASS ||
1185                            proto_ce->type == ZEND_INTERNAL_CLASS ||
1186                            fe_ce != proto_ce) {
1187                        zend_string_release(proto_class_name);
1188                        zend_string_release(fe_class_name);
1189                        return 0;
1190                    }
1191                }
1192            }
1193            zend_string_release(proto_class_name);
1194            zend_string_release(fe_class_name);
1195        }
1196        if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
1197            /* Incompatible type hint */
1198            return 0;
1199        }
1200
1201        /* by-ref constraints on arguments are invariant */
1202        if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
1203            return 0;
1204        }
1205    }
1206
1207    return 1;
1208}
1209/* }}} */
1210
1211#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
1212    if (UNEXPECTED(offset - buf + size >= length)) {    \
1213        length += size + 1;                 \
1214        buf = erealloc(buf, length);        \
1215    }
1216
1217static char *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
1218{
1219    char *offset, *buf;
1220    uint32_t length = 1024;
1221
1222    offset = buf = (char *)emalloc(length * sizeof(char));
1223    if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
1224        *(offset++) = '&';
1225        *(offset++) = ' ';
1226    }
1227
1228    if (fptr->common.scope) {
1229        memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len);
1230        offset += fptr->common.scope->name->len;
1231        *(offset++) = ':';
1232        *(offset++) = ':';
1233    }
1234
1235    {
1236        size_t name_len = fptr->common.function_name->len;
1237        REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
1238        memcpy(offset, fptr->common.function_name->val, name_len);
1239        offset += name_len;
1240    }
1241
1242    *(offset++) = '(';
1243    if (fptr->common.arg_info) {
1244        uint32_t i, required;
1245        zend_arg_info *arg_info = fptr->common.arg_info;
1246
1247        required = fptr->common.required_num_args;
1248        for (i = 0; i < fptr->common.num_args;) {
1249            if (arg_info->class_name) {
1250                const char *class_name;
1251                uint32_t class_name_len;
1252                if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
1253                    class_name = fptr->common.scope->name->val;
1254                    class_name_len = fptr->common.scope->name->len;
1255                } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
1256                    class_name = fptr->common.scope->parent->name->val;
1257                    class_name_len = fptr->common.scope->parent->name->len;
1258                } else {
1259                    class_name = arg_info->class_name;
1260                    class_name_len = arg_info->class_name_len;
1261                }
1262                REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
1263                memcpy(offset, class_name, class_name_len);
1264                offset += class_name_len;
1265                *(offset++) = ' ';
1266            } else if (arg_info->type_hint) {
1267                uint32_t type_name_len;
1268                char *type_name = zend_get_type_by_const(arg_info->type_hint);
1269                type_name_len = strlen(type_name);
1270                REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
1271                memcpy(offset, type_name, type_name_len);
1272                offset += type_name_len;
1273                *(offset++) = ' ';
1274            }
1275
1276            if (arg_info->pass_by_reference) {
1277                *(offset++) = '&';
1278            }
1279
1280            if (arg_info->is_variadic) {
1281                *(offset++) = '.';
1282                *(offset++) = '.';
1283                *(offset++) = '.';
1284            }
1285
1286            *(offset++) = '$';
1287
1288            if (arg_info->name) {
1289                REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
1290                memcpy(offset, arg_info->name, arg_info->name_len);
1291                offset += arg_info->name_len;
1292            } else {
1293                uint32_t idx = i;
1294                memcpy(offset, "param", 5);
1295                offset += 5;
1296                do {
1297                    *(offset++) = (char) (idx % 10) + '0';
1298                    idx /= 10;
1299                } while (idx > 0);
1300            }
1301            if (i >= required && !arg_info->is_variadic) {
1302                *(offset++) = ' ';
1303                *(offset++) = '=';
1304                *(offset++) = ' ';
1305                if (fptr->type == ZEND_USER_FUNCTION) {
1306                    zend_op *precv = NULL;
1307                    {
1308                        uint32_t idx  = i;
1309                        zend_op *op = ((zend_op_array *)fptr)->opcodes;
1310                        zend_op *end = op + ((zend_op_array *)fptr)->last;
1311
1312                        ++idx;
1313                        while (op < end) {
1314                            if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
1315                                    && op->op1.num == (zend_ulong)idx)
1316                            {
1317                                precv = op;
1318                            }
1319                            ++op;
1320                        }
1321                    }
1322                    if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
1323                        zval *zv = precv->op2.zv;
1324
1325                        if (Z_TYPE_P(zv) == IS_CONSTANT) {
1326                            REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
1327                            memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
1328                            offset += Z_STRLEN_P(zv);
1329                        } else if (Z_TYPE_P(zv) == IS_FALSE) {
1330                            memcpy(offset, "false", 5);
1331                            offset += 5;
1332                        } else if (Z_TYPE_P(zv) == IS_TRUE) {
1333                            memcpy(offset, "true", 4);
1334                            offset += 4;
1335                        } else if (Z_TYPE_P(zv) == IS_NULL) {
1336                            memcpy(offset, "NULL", 4);
1337                            offset += 4;
1338                        } else if (Z_TYPE_P(zv) == IS_STRING) {
1339                            *(offset++) = '\'';
1340                            REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
1341                            memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
1342                            offset += MIN(Z_STRLEN_P(zv), 10);
1343                            if (Z_STRLEN_P(zv) > 10) {
1344                                *(offset++) = '.';
1345                                *(offset++) = '.';
1346                                *(offset++) = '.';
1347                            }
1348                            *(offset++) = '\'';
1349                        } else if (Z_TYPE_P(zv) == IS_ARRAY) {
1350                            memcpy(offset, "Array", 5);
1351                            offset += 5;
1352                        } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1353                            memcpy(offset, "<expression>", 12);
1354                            offset += 12;
1355                        } else {
1356                            zend_string *str = zval_get_string(zv);
1357                            REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len);
1358                            memcpy(offset, str->val, str->len);
1359                            offset += str->len;
1360                            zend_string_release(str);
1361                        }
1362                    }
1363                } else {
1364                    memcpy(offset, "NULL", 4);
1365                    offset += 4;
1366                }
1367            }
1368
1369            if (++i < fptr->common.num_args) {
1370                *(offset++) = ',';
1371                *(offset++) = ' ';
1372            }
1373            arg_info++;
1374            REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
1375        }
1376    }
1377    *(offset++) = ')';
1378    *offset = '\0';
1379
1380    return buf;
1381}
1382/* }}} */
1383
1384static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
1385{
1386    uint32_t child_flags;
1387    uint32_t parent_flags = parent->common.fn_flags;
1388
1389    if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
1390        && parent->common.fn_flags & ZEND_ACC_ABSTRACT
1391        && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
1392        && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
1393        zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
1394            parent->common.scope->name->val,
1395            child->common.function_name->val,
1396            child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val);
1397    }
1398
1399    if (parent_flags & ZEND_ACC_FINAL) {
1400        zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val);
1401    }
1402
1403    child_flags = child->common.fn_flags;
1404    /* You cannot change from static to non static and vice versa.
1405     */
1406    if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
1407        if (child->common.fn_flags & ZEND_ACC_STATIC) {
1408            zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
1409        } else {
1410            zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
1411        }
1412    }
1413
1414    /* Disallow making an inherited method abstract. */
1415    if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
1416        zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
1417    }
1418
1419    if (parent_flags & ZEND_ACC_CHANGED) {
1420        child->common.fn_flags |= ZEND_ACC_CHANGED;
1421    } else {
1422        /* Prevent derived classes from restricting access that was available in parent classes
1423         */
1424        if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1425            zend_error_noreturn(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->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1426        } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
1427            && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
1428            child->common.fn_flags |= ZEND_ACC_CHANGED;
1429        }
1430    }
1431
1432    if (parent_flags & ZEND_ACC_PRIVATE) {
1433        child->common.prototype = NULL;
1434    } else if (parent_flags & ZEND_ACC_ABSTRACT) {
1435        child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
1436        child->common.prototype = parent;
1437    } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
1438        /* ctors only have a prototype if it comes from an interface */
1439        child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1440    }
1441
1442    if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1443        if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
1444            zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
1445        }
1446    } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
1447        if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
1448            char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
1449            zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype);
1450            efree(method_prototype);
1451        }
1452    }
1453}
1454/* }}} */
1455
1456static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, zend_string *key, zend_class_entry *child_ce) /* {{{ */
1457{
1458    uint32_t parent_flags = parent->common.fn_flags;
1459    zend_function *child;
1460    TSRMLS_FETCH();
1461
1462    if ((child = zend_hash_find_ptr(child_function_table, key)) == NULL) {
1463        if (parent_flags & (ZEND_ACC_ABSTRACT)) {
1464            child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1465        }
1466        return 1; /* method doesn't exist in child, copy from parent */
1467    }
1468
1469    do_inheritance_check_on_method(child, parent TSRMLS_CC);
1470
1471    return 0;
1472}
1473/* }}} */
1474
1475static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, zend_string *key, zend_class_entry *ce TSRMLS_DC) /* {{{ */
1476{
1477    zend_property_info *child_info;
1478    zend_class_entry *parent_ce = ce->parent;
1479
1480    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
1481        if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
1482            child_info->flags |= ZEND_ACC_CHANGED;
1483        } else {
1484            if(ce->type & ZEND_INTERNAL_CLASS) {
1485                child_info = zend_duplicate_property_info_internal(parent_info);
1486            } else {
1487                child_info = zend_duplicate_property_info(parent_info TSRMLS_CC);
1488            }
1489            zend_hash_update_ptr(&ce->properties_info, key, child_info);
1490            child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
1491            child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
1492        }
1493        return 0; /* don't copy access information to child */
1494    }
1495
1496    if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
1497        if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
1498            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1499                (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val,
1500                (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val);
1501
1502        }
1503
1504        if(parent_info->flags & ZEND_ACC_CHANGED) {
1505            child_info->flags |= ZEND_ACC_CHANGED;
1506        }
1507
1508        if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
1509            zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1510        } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
1511            zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
1512            ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
1513            ZVAL_UNDEF(&ce->default_properties_table[child_info->offset]);
1514            child_info->offset = parent_info->offset;
1515        }
1516        return 0;   /* Don't copy from parent */
1517    } else {
1518        return 1;   /* Copy from parent */
1519    }
1520}
1521/* }}} */
1522
1523static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1524{
1525    if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
1526        zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name->val, iface->name->val);
1527    }
1528    if (ce == iface) {
1529        zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name->val);
1530    }
1531}
1532/* }}} */
1533
1534ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
1535{
1536    /* expects interface to be contained in ce's interface list already */
1537    uint32_t i, ce_num, if_num = iface->num_interfaces;
1538    zend_class_entry *entry;
1539
1540    if (if_num==0) {
1541        return;
1542    }
1543    ce_num = ce->num_interfaces;
1544
1545    if (ce->type == ZEND_INTERNAL_CLASS) {
1546        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1547    } else {
1548        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1549    }
1550
1551    /* Inherit the interfaces, only if they're not already inherited by the class */
1552    while (if_num--) {
1553        entry = iface->interfaces[if_num];
1554        for (i = 0; i < ce_num; i++) {
1555            if (ce->interfaces[i] == entry) {
1556                break;
1557            }
1558        }
1559        if (i == ce_num) {
1560            ce->interfaces[ce->num_interfaces++] = entry;
1561        }
1562    }
1563
1564    /* and now call the implementing handlers */
1565    while (ce_num < ce->num_interfaces) {
1566        do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
1567    }
1568}
1569/* }}} */
1570
1571#ifdef ZTS
1572# define zval_property_ctor(parent_ce, ce) \
1573    (((parent_ce)->type != (ce)->type) ? ZVAL_COPY_CTOR : zval_add_ref)
1574#else
1575# define zval_property_ctor(parent_ce, ce) \
1576    zval_add_ref
1577#endif
1578
1579static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
1580{
1581    if (!Z_ISREF_P(zv)) {
1582        if (parent_ce->type == ZEND_INTERNAL_CLASS) {
1583            ZVAL_NEW_PERSISTENT_REF(zv, zv);
1584        } else {
1585            ZVAL_NEW_REF(zv, zv);
1586        }
1587    }
1588    if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
1589        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1590    }
1591    if (zend_hash_add(&ce->constants_table, name, zv)) {
1592        Z_ADDREF_P(zv);
1593    }
1594}
1595/* }}} */
1596
1597ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
1598{
1599    zend_property_info *property_info;
1600    zend_function *func;
1601    zend_string *key;
1602    zval *zv;
1603
1604    if ((ce->ce_flags & ZEND_ACC_INTERFACE)
1605        && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
1606        zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val);
1607    }
1608    if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
1609        zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val);
1610    }
1611
1612    ce->parent = parent_ce;
1613    /* Copy serialize/unserialize callbacks */
1614    if (!ce->serialize) {
1615        ce->serialize   = parent_ce->serialize;
1616    }
1617    if (!ce->unserialize) {
1618        ce->unserialize = parent_ce->unserialize;
1619    }
1620
1621    /* Inherit interfaces */
1622    zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
1623
1624    /* Inherit properties */
1625    if (parent_ce->default_properties_count) {
1626        int i = ce->default_properties_count + parent_ce->default_properties_count;
1627
1628        ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
1629        if (ce->default_properties_count) {
1630            while (i-- > parent_ce->default_properties_count) {
1631                ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
1632            }
1633        }
1634        for (i = 0; i < parent_ce->default_properties_count; i++) {
1635#ifdef ZTS
1636            if (parent_ce->type != ce->type) {
1637                ZVAL_DUP(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
1638                if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
1639                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1640                }
1641                continue;
1642            }
1643#endif
1644
1645            ZVAL_COPY(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
1646            if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
1647                ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1648            }
1649        }
1650        ce->default_properties_count += parent_ce->default_properties_count;
1651    }
1652
1653    if (parent_ce->type != ce->type) {
1654        /* User class extends internal class */
1655        zend_update_class_constants(parent_ce  TSRMLS_CC);
1656        if (parent_ce->default_static_members_count) {
1657            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
1658
1659            ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(zval) * i);
1660            if (ce->default_static_members_count) {
1661                while (i-- > parent_ce->default_static_members_count) {
1662                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
1663                }
1664            }
1665            for (i = 0; i < parent_ce->default_static_members_count; i++) {
1666                ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
1667                ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
1668                Z_ADDREF(ce->default_static_members_table[i]);
1669                if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
1670                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1671                }
1672            }
1673            ce->default_static_members_count += parent_ce->default_static_members_count;
1674            ce->static_members_table = ce->default_static_members_table;
1675        }
1676    } else {
1677        if (parent_ce->default_static_members_count) {
1678            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
1679
1680            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
1681            if (ce->default_static_members_count) {
1682                while (i-- > parent_ce->default_static_members_count) {
1683                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
1684                }
1685            }
1686            for (i = 0; i < parent_ce->default_static_members_count; i++) {
1687                ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
1688                ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
1689                Z_ADDREF(ce->default_static_members_table[i]);
1690                if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
1691                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1692                }
1693            }
1694            ce->default_static_members_count += parent_ce->default_static_members_count;
1695            if (ce->type == ZEND_USER_CLASS) {
1696                ce->static_members_table = ce->default_static_members_table;
1697            }
1698        }
1699    }
1700
1701    ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
1702        if (property_info->ce == ce) {
1703            if (property_info->flags & ZEND_ACC_STATIC) {
1704                property_info->offset += parent_ce->default_static_members_count;
1705            } else {
1706                property_info->offset += parent_ce->default_properties_count;
1707            }
1708        }
1709    } ZEND_HASH_FOREACH_END();
1710
1711    ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1712        if (do_inherit_property_access_check(&ce->properties_info, property_info, key, ce TSRMLS_CC)) {
1713            if (ce->type & ZEND_INTERNAL_CLASS) {
1714                property_info = zend_duplicate_property_info_internal(property_info);
1715            } else {
1716                property_info = zend_duplicate_property_info(property_info TSRMLS_CC);
1717            }
1718            zend_hash_add_new_ptr(&ce->properties_info, key, property_info);
1719        }
1720    } ZEND_HASH_FOREACH_END();
1721
1722    ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
1723        do_inherit_class_constant(key, zv, ce, parent_ce TSRMLS_CC);
1724    } ZEND_HASH_FOREACH_END();
1725
1726    ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1727        if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
1728            zend_function *new_func = do_inherit_method(func TSRMLS_CC);
1729            zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1730        }
1731    } ZEND_HASH_FOREACH_END();
1732
1733    do_inherit_parent_constructor(ce TSRMLS_CC);
1734
1735    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
1736        ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1737    } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
1738        /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
1739        zend_verify_abstract_class(ce TSRMLS_CC);
1740    }
1741    ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
1742}
1743/* }}} */
1744
1745static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
1746{
1747    zval *old_constant;
1748
1749    if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
1750        if (!Z_ISREF_P(old_constant) ||
1751            !Z_ISREF_P(parent_constant) ||
1752            Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
1753            zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", name->val, iface->name->val);
1754        }
1755        return 0;
1756    }
1757    return 1;
1758}
1759/* }}} */
1760
1761static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1762{
1763    if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
1764        ZVAL_MAKE_REF(zv);
1765        Z_ADDREF_P(zv);
1766        if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
1767            ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1768        }
1769        zend_hash_update(&ce->constants_table, name, zv);
1770    }
1771}
1772/* }}} */
1773
1774ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1775{
1776    uint32_t i, ignore = 0;
1777    uint32_t current_iface_num = ce->num_interfaces;
1778    uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
1779    zend_function *func;
1780    zend_string *key;
1781    zval *zv;
1782
1783    for (i = 0; i < ce->num_interfaces; i++) {
1784        if (ce->interfaces[i] == NULL) {
1785            memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1786            i--;
1787        } else if (ce->interfaces[i] == iface) {
1788            if (i < parent_iface_num) {
1789                ignore = 1;
1790            } else {
1791                zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name->val, iface->name->val);
1792            }
1793        }
1794    }
1795    if (ignore) {
1796        /* Check for attempt to redeclare interface constants */
1797        ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
1798            do_inherit_constant_check(&iface->constants_table, zv, key, iface);
1799        } ZEND_HASH_FOREACH_END();
1800    } else {
1801        if (ce->num_interfaces >= current_iface_num) {
1802            if (ce->type == ZEND_INTERNAL_CLASS) {
1803                ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1804            } else {
1805                ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1806            }
1807        }
1808        ce->interfaces[ce->num_interfaces++] = iface;
1809
1810        ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
1811            do_inherit_iface_constant(key, zv, ce, iface TSRMLS_CC);
1812        } ZEND_HASH_FOREACH_END();
1813
1814        ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1815            if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
1816                zend_function *new_func = do_inherit_method(func TSRMLS_CC);
1817                zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1818            }
1819        } ZEND_HASH_FOREACH_END();
1820
1821        do_implement_interface(ce, iface TSRMLS_CC);
1822        zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
1823    }
1824}
1825/* }}} */
1826
1827ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
1828{
1829    uint32_t i, ignore = 0;
1830    uint32_t current_trait_num = ce->num_traits;
1831    uint32_t parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
1832
1833    for (i = 0; i < ce->num_traits; i++) {
1834        if (ce->traits[i] == NULL) {
1835            memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
1836            i--;
1837        } else if (ce->traits[i] == trait) {
1838            if (i < parent_trait_num) {
1839                ignore = 1;
1840            }
1841        }
1842    }
1843    if (!ignore) {
1844        if (ce->num_traits >= current_trait_num) {
1845            if (ce->type == ZEND_INTERNAL_CLASS) {
1846                ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1847            } else {
1848                ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1849            }
1850        }
1851        ce->traits[ce->num_traits++] = trait;
1852    }
1853}
1854/* }}} */
1855
1856static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
1857{
1858    uint32_t    fn_flags = fn->common.scope->ce_flags;
1859    uint32_t other_flags = other_fn->common.scope->ce_flags;
1860
1861    return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
1862        && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
1863        && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
1864            (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
1865}
1866/* }}} */
1867
1868static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe TSRMLS_DC) /* {{{ */
1869{
1870    if (!strncmp(mname->val, ZEND_CLONE_FUNC_NAME, mname->len)) {
1871        ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
1872    } else if (!strncmp(mname->val, ZEND_CONSTRUCTOR_FUNC_NAME, mname->len)) {
1873        if (ce->constructor) {
1874            zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
1875        }
1876        ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
1877    } else if (!strncmp(mname->val, ZEND_DESTRUCTOR_FUNC_NAME,  mname->len)) {
1878        ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
1879    } else if (!strncmp(mname->val, ZEND_GET_FUNC_NAME, mname->len)) {
1880        ce->__get = fe;
1881    } else if (!strncmp(mname->val, ZEND_SET_FUNC_NAME, mname->len)) {
1882        ce->__set = fe;
1883    } else if (!strncmp(mname->val, ZEND_CALL_FUNC_NAME, mname->len)) {
1884        ce->__call = fe;
1885    } else if (!strncmp(mname->val, ZEND_UNSET_FUNC_NAME, mname->len)) {
1886        ce->__unset = fe;
1887    } else if (!strncmp(mname->val, ZEND_ISSET_FUNC_NAME, mname->len)) {
1888        ce->__isset = fe;
1889    } else if (!strncmp(mname->val, ZEND_CALLSTATIC_FUNC_NAME, mname->len)) {
1890        ce->__callstatic = fe;
1891    } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) {
1892        ce->__tostring = fe;
1893    } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) {
1894        ce->__debugInfo = fe;
1895    } else if (ce->name->len == mname->len) {
1896        zend_string *lowercase_name = zend_string_alloc(ce->name->len, 0);
1897        zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len);
1898        lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
1899        if (!memcmp(mname->val, lowercase_name->val, mname->len)) {
1900            if (ce->constructor) {
1901                zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
1902            }
1903            ce->constructor = fe;
1904            fe->common.fn_flags |= ZEND_ACC_CTOR;
1905        }
1906        zend_string_release(lowercase_name);
1907    }
1908}
1909/* }}} */
1910
1911static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
1912{
1913    zend_function *existing_fn = NULL;
1914    zend_function *new_fn;
1915
1916    if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1917        if (existing_fn->common.scope == ce) {
1918            /* members from the current class override trait methods */
1919            /* use temporary *overriden HashTable to detect hidden conflict */
1920            if (*overriden) {
1921                if ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
1922                    if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1923                        /* Make sure the trait method is compatible with previosly declared abstract method */
1924                        if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
1925                            zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1926                                zend_get_function_declaration(fn TSRMLS_CC),
1927                                zend_get_function_declaration(existing_fn TSRMLS_CC));
1928                        }
1929                    } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1930                        /* Make sure the abstract declaration is compatible with previous declaration */
1931                        if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
1932                            zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1933                                zend_get_function_declaration(fn TSRMLS_CC),
1934                                zend_get_function_declaration(existing_fn TSRMLS_CC));
1935                        }
1936                        return;
1937                    }
1938                }
1939            } else {
1940                ALLOC_HASHTABLE(*overriden);
1941                zend_hash_init_ex(*overriden, 8, NULL, ptr_dtor, 0, 0);
1942            }
1943            fn = zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
1944            return;
1945        } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1946            /* Make sure the trait method is compatible with previosly declared abstract method */
1947            if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
1948                zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1949                    zend_get_function_declaration(fn TSRMLS_CC),
1950                    zend_get_function_declaration(existing_fn TSRMLS_CC));
1951            }
1952        } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1953            /* Make sure the abstract declaration is compatible with previous declaration */
1954            if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
1955                zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1956                    zend_get_function_declaration(fn TSRMLS_CC),
1957                    zend_get_function_declaration(existing_fn TSRMLS_CC));
1958            }
1959            return;
1960        } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1961            /* two traits can't define the same non-abstract method */
1962#if 1
1963            zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
1964                name, ce->name->val);
1965#else       /* TODO: better error message */
1966            zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1967                fn->common.scope->name->val, fn->common.function_name->val,
1968                ce->name->val, name,
1969                existing_fn->common.scope->name->val, existing_fn->common.function_name->val);
1970#endif
1971        } else {
1972            /* inherited members are overridden by members inserted by traits */
1973            /* check whether the trait method fulfills the inheritance requirements */
1974            do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
1975        }
1976    }
1977
1978    function_add_ref(fn);
1979    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1980    memcpy(new_fn, fn, sizeof(zend_op_array));
1981    fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1982    zend_add_magic_methods(ce, key, fn TSRMLS_CC);
1983}
1984/* }}} */
1985
1986static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1987{
1988    if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1989
1990        fn->common.scope = ce;
1991
1992        if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1993            ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1994        }
1995        if (fn->op_array.static_variables) {
1996            ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1997        }
1998    }
1999}
2000/* }}} */
2001
2002static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table TSRMLS_DC) /* {{{ */
2003{
2004    zend_trait_alias  *alias, **alias_ptr;
2005    zend_string       *lcname;
2006    zend_function      fn_copy;
2007
2008    /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2009    if (ce->trait_aliases) {
2010        alias_ptr = ce->trait_aliases;
2011        alias = *alias_ptr;
2012        while (alias) {
2013            /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2014            if (alias->alias != NULL
2015                && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
2016                && alias->trait_method->method_name->len == fnname->len
2017                && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
2018                fn_copy = *fn;
2019
2020                /* if it is 0, no modifieres has been changed */
2021                if (alias->modifiers) {
2022                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
2023                }
2024
2025                lcname = zend_string_alloc(alias->alias->len, 0);
2026                zend_str_tolower_copy(lcname->val, alias->alias->val, alias->alias->len);
2027                zend_add_trait_method(ce, alias->alias->val, lcname, &fn_copy, overriden TSRMLS_CC);
2028                zend_string_release(lcname);
2029
2030                /* Record the trait from which this alias was resolved. */
2031                if (!alias->trait_method->ce) {
2032                    alias->trait_method->ce = fn->common.scope;
2033                }
2034            }
2035            alias_ptr++;
2036            alias = *alias_ptr;
2037        }
2038    }
2039
2040    if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2041        /* is not in hashtable, thus, function is not to be excluded */
2042        fn_copy = *fn;
2043
2044        /* apply aliases which have not alias name, just setting visibility */
2045        if (ce->trait_aliases) {
2046            alias_ptr = ce->trait_aliases;
2047            alias = *alias_ptr;
2048            while (alias) {
2049                /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2050                if (alias->alias == NULL && alias->modifiers != 0
2051                    && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
2052                    && (alias->trait_method->method_name->len == fnname->len)
2053                    && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
2054
2055                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
2056
2057                    /** Record the trait from which this alias was resolved. */
2058                    if (!alias->trait_method->ce) {
2059                        alias->trait_method->ce = fn->common.scope;
2060                    }
2061                }
2062                alias_ptr++;
2063                alias = *alias_ptr;
2064            }
2065        }
2066
2067        zend_add_trait_method(ce, fn->common.function_name->val, fnname, &fn_copy, overriden TSRMLS_CC);
2068    }
2069
2070    return ZEND_HASH_APPLY_KEEP;
2071}
2072/* }}} */
2073
2074static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
2075{
2076    uint32_t i;
2077
2078    if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
2079        zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name->val);
2080    }
2081
2082    for (i = 0; i < ce->num_traits; i++) {
2083        if (ce->traits[i] == trait) {
2084            return;
2085        }
2086    }
2087    zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name->val, ce->name->val);
2088}
2089/* }}} */
2090
2091static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2092{
2093    size_t i, j = 0;
2094    zend_trait_precedence *cur_precedence;
2095    zend_trait_method_reference *cur_method_ref;
2096    zend_string *lcname;
2097    zend_bool method_exists;
2098
2099    /* resolve class references */
2100    if (ce->trait_precedences) {
2101        i = 0;
2102        while ((cur_precedence = ce->trait_precedences[i])) {
2103            /** Resolve classes for all precedence operations. */
2104            if (cur_precedence->exclude_from_classes) {
2105                cur_method_ref = cur_precedence->trait_method;
2106                if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
2107                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2108                    zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
2109                }
2110                zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
2111
2112                /** Ensure that the prefered method is actually available. */
2113                lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
2114                zend_str_tolower_copy(lcname->val,
2115                    cur_method_ref->method_name->val,
2116                    cur_method_ref->method_name->len);
2117                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
2118                                                 lcname);
2119                zend_string_free(lcname);
2120                if (!method_exists) {
2121                    zend_error_noreturn(E_COMPILE_ERROR,
2122                               "A precedence rule was defined for %s::%s but this method does not exist",
2123                               cur_method_ref->ce->name->val,
2124                               cur_method_ref->method_name->val);
2125                }
2126
2127                /** With the other traits, we are more permissive.
2128                    We do not give errors for those. This allows to be more
2129                    defensive in such definitions.
2130                    However, we want to make sure that the insteadof declaration
2131                    is consistent in itself.
2132                 */
2133                j = 0;
2134                while (cur_precedence->exclude_from_classes[j].class_name) {
2135                    zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
2136
2137                    if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2138                        zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", class_name->val);
2139                    }
2140                    zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce TSRMLS_CC);
2141
2142                    /* make sure that the trait method is not from a class mentioned in
2143                     exclude_from_classes, for consistency */
2144                    if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i].ce) {
2145                        zend_error_noreturn(E_COMPILE_ERROR,
2146                                   "Inconsistent insteadof definition. "
2147                                   "The method %s is to be used from %s, but %s is also on the exclude list",
2148                                   cur_method_ref->method_name->val,
2149                                   cur_precedence->trait_method->ce->name->val,
2150                                   cur_precedence->trait_method->ce->name->val);
2151                    }
2152
2153                    zend_string_release(class_name);
2154                    j++;
2155                }
2156            }
2157            i++;
2158        }
2159    }
2160
2161    if (ce->trait_aliases) {
2162        i = 0;
2163        while (ce->trait_aliases[i]) {
2164            /** For all aliases with an explicit class name, resolve the class now. */
2165            if (ce->trait_aliases[i]->trait_method->class_name) {
2166                cur_method_ref = ce->trait_aliases[i]->trait_method;
2167                if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2168                    zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
2169                }
2170                zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
2171
2172                /** And, ensure that the referenced method is resolvable, too. */
2173                lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
2174                zend_str_tolower_copy(lcname->val,
2175                    cur_method_ref->method_name->val,
2176                    cur_method_ref->method_name->len);
2177                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
2178                        lcname);
2179                zend_string_free(lcname);
2180
2181                if (!method_exists) {
2182                    zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name->val, cur_method_ref->method_name->val);
2183                }
2184            }
2185            i++;
2186        }
2187    }
2188}
2189/* }}} */
2190
2191static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
2192{
2193    size_t i = 0, j;
2194
2195    if (!precedences) {
2196        return;
2197    }
2198    while (precedences[i]) {
2199        if (precedences[i]->exclude_from_classes) {
2200            j = 0;
2201            while (precedences[i]->exclude_from_classes[j].ce) {
2202                if (precedences[i]->exclude_from_classes[j].ce == trait) {
2203                    zend_string *lcname = zend_string_alloc(precedences[i]->trait_method->method_name->len, 0);
2204
2205                    zend_str_tolower_copy(lcname->val,
2206                        precedences[i]->trait_method->method_name->val,
2207                        precedences[i]->trait_method->method_name->len);
2208                    if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
2209                        zend_string_release(lcname);
2210                        zend_error_noreturn(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->val, trait->name->val);
2211                    }
2212                    zend_string_release(lcname);
2213                }
2214                ++j;
2215            }
2216        }
2217        ++i;
2218    }
2219}
2220/* }}} */
2221
2222static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2223{
2224    uint32_t i;
2225    HashTable *overriden = NULL;
2226    zend_string *key;
2227    zend_function *fn;
2228
2229    for (i = 0; i < ce->num_traits; i++) {
2230        if (ce->trait_precedences) {
2231            HashTable exclude_table;
2232
2233            /* TODO: revisit this start size, may be its not optimal */
2234            zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
2235
2236            zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
2237
2238            /* copies functions, applies defined aliasing, and excludes unused trait methods */
2239            ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
2240                zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table TSRMLS_CC);
2241            } ZEND_HASH_FOREACH_END();
2242
2243            zend_hash_destroy(&exclude_table);
2244        } else {
2245            ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
2246                zend_traits_copy_functions(key, fn, ce, &overriden, NULL TSRMLS_CC);
2247            } ZEND_HASH_FOREACH_END();
2248        }
2249    }
2250
2251    ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
2252        zend_fixup_trait_method(fn, ce);
2253    } ZEND_HASH_FOREACH_END();
2254
2255    if (overriden) {
2256        zend_hash_destroy(overriden);
2257        FREE_HASHTABLE(overriden);
2258    }
2259}
2260/* }}} */
2261
2262static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
2263{
2264    size_t i;
2265
2266    if (coliding_ce == ce) {
2267        for (i = 0; i < current_trait; i++) {
2268            if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
2269                return ce->traits[i];
2270            }
2271        }
2272    }
2273
2274    return coliding_ce;
2275}
2276/* }}} */
2277
2278static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2279{
2280    size_t i;
2281    zend_property_info *property_info;
2282    zend_property_info *coliding_prop;
2283    zval compare_result;
2284    zend_string* prop_name;
2285    const char* class_name_unused;
2286    zend_bool not_compatible;
2287    zval* prop_value;
2288    uint32_t flags;
2289    zend_string *doc_comment;
2290
2291    /* In the following steps the properties are inserted into the property table
2292     * for that, a very strict approach is applied:
2293     * - check for compatibility, if not compatible with any property in class -> fatal
2294     * - if compatible, then strict notice
2295     */
2296    for (i = 0; i < ce->num_traits; i++) {
2297        ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
2298            /* first get the unmangeld name if necessary,
2299             * then check whether the property is already there
2300             */
2301            flags = property_info->flags;
2302            if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
2303                prop_name = zend_string_copy(property_info->name);
2304            } else {
2305                const char *pname;
2306                int pname_len;
2307
2308                /* for private and protected we need to unmangle the names */
2309                zend_unmangle_property_name_ex(property_info->name->val, property_info->name->len,
2310                                            &class_name_unused, &pname, &pname_len);
2311                prop_name = zend_string_init(pname, pname_len, 0);
2312            }
2313
2314            /* next: check for conflicts with current class */
2315            if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2316                if (coliding_prop->flags & ZEND_ACC_SHADOW) {
2317                    zend_hash_del(&ce->properties_info, prop_name);
2318                    flags |= ZEND_ACC_CHANGED;
2319                } else {
2320                    if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
2321                        == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
2322                        /* flags are identical, now the value needs to be checked */
2323                        if (flags & ZEND_ACC_STATIC) {
2324                            not_compatible = (FAILURE == compare_function(&compare_result,
2325                                              &ce->default_static_members_table[coliding_prop->offset],
2326                                              &ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
2327                                  || (Z_LVAL(compare_result) != 0);
2328                        } else {
2329                            not_compatible = (FAILURE == compare_function(&compare_result,
2330                                              &ce->default_properties_table[coliding_prop->offset],
2331                                              &ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
2332                                  || (Z_LVAL(compare_result) != 0);
2333                        }
2334                    } else {
2335                        /* the flags are not identical, thus, we assume properties are not compatible */
2336                        not_compatible = 1;
2337                    }
2338
2339                    if (not_compatible) {
2340                        zend_error_noreturn(E_COMPILE_ERROR,
2341                               "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2342                                find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
2343                                property_info->ce->name->val,
2344                                prop_name->val,
2345                                ce->name->val);
2346                    } else {
2347                        zend_error(E_STRICT,
2348                               "%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",
2349                                find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
2350                                property_info->ce->name->val,
2351                                prop_name->val,
2352                                ce->name->val);
2353                        zend_string_release(prop_name);
2354                        continue;
2355                    }
2356                }
2357            }
2358
2359            /* property not found, so lets add it */
2360            if (flags & ZEND_ACC_STATIC) {
2361                prop_value = &ce->traits[i]->default_static_members_table[property_info->offset];
2362            } else {
2363                prop_value = &ce->traits[i]->default_properties_table[property_info->offset];
2364            }
2365            if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
2366
2367            doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2368            zend_declare_property_ex(ce, prop_name,
2369                                     prop_value, flags,
2370                                     doc_comment TSRMLS_CC);
2371            zend_string_release(prop_name);
2372        } ZEND_HASH_FOREACH_END();
2373    }
2374}
2375/* }}} */
2376
2377static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2378{
2379    int i = 0;
2380    zend_trait_alias* cur_alias;
2381    zend_string* lc_method_name;
2382
2383    if (ce->trait_aliases) {
2384        while (ce->trait_aliases[i]) {
2385            cur_alias = ce->trait_aliases[i];
2386            /** The trait for this alias has not been resolved, this means, this
2387                alias was not applied. Abort with an error. */
2388            if (!cur_alias->trait_method->ce) {
2389                if (cur_alias->alias) {
2390                    /** Plain old inconsistency/typo/bug */
2391                    zend_error_noreturn(E_COMPILE_ERROR,
2392                               "An alias (%s) was defined for method %s(), but this method does not exist",
2393                               cur_alias->alias->val,
2394                               cur_alias->trait_method->method_name->val);
2395                } else {
2396                    /** Here are two possible cases:
2397                        1) this is an attempt to modifiy the visibility
2398                           of a method introduce as part of another alias.
2399                           Since that seems to violate the DRY principle,
2400                           we check against it and abort.
2401                        2) it is just a plain old inconsitency/typo/bug
2402                           as in the case where alias is set. */
2403
2404                    lc_method_name = zend_string_alloc(cur_alias->trait_method->method_name->len, 0);
2405                    zend_str_tolower_copy(
2406                        lc_method_name->val,
2407                        cur_alias->trait_method->method_name->val,
2408                        cur_alias->trait_method->method_name->len);
2409                    if (zend_hash_exists(&ce->function_table,
2410                                         lc_method_name)) {
2411                        zend_string_free(lc_method_name);
2412                        zend_error_noreturn(E_COMPILE_ERROR,
2413                                   "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
2414                                   cur_alias->trait_method->method_name->val);
2415                    } else {
2416                        zend_string_free(lc_method_name);
2417                        zend_error_noreturn(E_COMPILE_ERROR,
2418                                   "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2419                                   cur_alias->trait_method->method_name->val);
2420
2421                    }
2422                }
2423            }
2424            i++;
2425        }
2426    }
2427}
2428/* }}} */
2429
2430ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2431{
2432
2433    if (ce->num_traits <= 0) {
2434        return;
2435    }
2436
2437    /* complete initialization of trait strutures in ce */
2438    zend_traits_init_trait_structures(ce TSRMLS_CC);
2439
2440    /* first care about all methods to be flattened into the class */
2441    zend_do_traits_method_binding(ce TSRMLS_CC);
2442
2443    /* Aliases which have not been applied indicate typos/bugs. */
2444    zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
2445
2446    /* then flatten the properties into it, to, mostly to notfiy developer about problems */
2447    zend_do_traits_property_binding(ce TSRMLS_CC);
2448
2449    /* verify that all abstract methods from traits have been implemented */
2450    zend_verify_abstract_class(ce TSRMLS_CC);
2451
2452    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
2453    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
2454        ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2455    }
2456}
2457/* }}} */
2458
2459ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
2460{
2461    zend_function *function, *new_function;
2462    zval *op1, *op2;
2463
2464    if (compile_time) {
2465        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2466        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2467    } else {
2468        op1 = opline->op1.zv;
2469        op2 = opline->op2.zv;
2470    }
2471
2472    function = zend_hash_find_ptr(function_table, Z_STR_P(op1));
2473    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2474    memcpy(new_function, function, sizeof(zend_op_array));
2475    if (zend_hash_add_ptr(function_table, Z_STR_P(op2), new_function) == NULL) {
2476        int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
2477        zend_function *old_function;
2478
2479        efree_size(new_function, sizeof(zend_op_array));
2480        if ((old_function = zend_hash_find_ptr(function_table, Z_STR_P(op2))) != NULL
2481            && old_function->type == ZEND_USER_FUNCTION
2482            && old_function->op_array.last > 0) {
2483            zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
2484                        function->common.function_name->val,
2485                        old_function->op_array.filename->val,
2486                        old_function->op_array.opcodes[0].lineno);
2487        } else {
2488            zend_error(error_level, "Cannot redeclare %s()", function->common.function_name->val);
2489        }
2490        return FAILURE;
2491    } else {
2492        (*function->op_array.refcount)++;
2493        function->op_array.static_variables = NULL; /* NULL out the unbound function */
2494        return SUCCESS;
2495    }
2496}
2497/* }}} */
2498
2499ZEND_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) /* {{{ */
2500{
2501    zend_class_entry *ce;
2502    zval *op1, *op2;
2503
2504    if (compile_time) {
2505        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2506        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2507    } else {
2508        op1 = opline->op1.zv;
2509        op2 = opline->op2.zv;
2510    }
2511    if ((ce = zend_hash_find_ptr(class_table, Z_STR_P(op1))) == NULL) {
2512        zend_error_noreturn(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
2513        return NULL;
2514    }
2515    ce->refcount++;
2516    if (zend_hash_add_ptr(class_table, Z_STR_P(op2), ce) == NULL) {
2517        ce->refcount--;
2518        if (!compile_time) {
2519            /* If we're in compile time, in practice, it's quite possible
2520             * that we'll never reach this class declaration at runtime,
2521             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
2522             * approach to work.
2523             */
2524            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name->val);
2525        }
2526        return NULL;
2527    } else {
2528        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
2529            zend_verify_abstract_class(ce TSRMLS_CC);
2530        }
2531        return ce;
2532    }
2533}
2534/* }}} */
2535
2536ZEND_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) /* {{{ */
2537{
2538    zend_class_entry *ce;
2539    zval *op1, *op2;
2540
2541    if (compile_time) {
2542        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2543        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2544    } else {
2545        op1 = opline->op1.zv;
2546        op2 = opline->op2.zv;
2547    }
2548
2549    ce = zend_hash_find_ptr(class_table, Z_STR_P(op1));
2550
2551    if (!ce) {
2552        if (!compile_time) {
2553            /* If we're in compile time, in practice, it's quite possible
2554             * that we'll never reach this class declaration at runtime,
2555             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
2556             * approach to work.
2557             */
2558            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
2559        }
2560        return NULL;
2561    }
2562
2563    if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
2564        zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name->val, parent_ce->name->val);
2565    } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2566        zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name->val, parent_ce->name->val);
2567    }
2568
2569    zend_do_inheritance(ce, parent_ce TSRMLS_CC);
2570
2571    ce->refcount++;
2572
2573    /* Register the derived class */
2574    if (zend_hash_add_ptr(class_table, Z_STR_P(op2), ce) == NULL) {
2575        zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name->val);
2576    }
2577    return ce;
2578}
2579/* }}} */
2580
2581void zend_do_early_binding(TSRMLS_D) /* {{{ */
2582{
2583    zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
2584    HashTable *table;
2585
2586    while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
2587        opline--;
2588    }
2589
2590    switch (opline->opcode) {
2591        case ZEND_DECLARE_FUNCTION:
2592            if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1 TSRMLS_CC) == FAILURE) {
2593                return;
2594            }
2595            table = CG(function_table);
2596            break;
2597        case ZEND_DECLARE_CLASS:
2598            if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
2599                return;
2600            }
2601            table = CG(class_table);
2602            break;
2603        case ZEND_DECLARE_INHERITED_CLASS:
2604            {
2605                zend_op *fetch_class_opline = opline-1;
2606                zval *parent_name;
2607                zend_class_entry *ce;
2608
2609                parent_name = &CONSTANT(fetch_class_opline->op2.constant);
2610                if (((ce = zend_lookup_class(Z_STR_P(parent_name) TSRMLS_CC)) == NULL) ||
2611                    ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
2612                     (ce->type == ZEND_INTERNAL_CLASS))) {
2613                    if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) {
2614                        uint32_t *opline_num = &CG(active_op_array)->early_binding;
2615
2616                        while (*opline_num != -1) {
2617                            opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num;
2618                        }
2619                        *opline_num = opline - CG(active_op_array)->opcodes;
2620                        opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
2621                        opline->result_type = IS_UNUSED;
2622                        opline->result.opline_num = -1;
2623                    }
2624                    return;
2625                }
2626                if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), ce, 1 TSRMLS_CC) == NULL) {
2627                    return;
2628                }
2629                /* clear unnecessary ZEND_FETCH_CLASS opcode */
2630                zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
2631                MAKE_NOP(fetch_class_opline);
2632
2633                table = CG(class_table);
2634                break;
2635            }
2636        case ZEND_VERIFY_ABSTRACT_CLASS:
2637        case ZEND_ADD_INTERFACE:
2638        case ZEND_ADD_TRAIT:
2639        case ZEND_BIND_TRAITS:
2640            /* We currently don't early-bind classes that implement interfaces */
2641            /* Classes with traits are handled exactly the same, no early-bind here */
2642            return;
2643        default:
2644            zend_error_noreturn(E_COMPILE_ERROR, "Invalid binding type");
2645            return;
2646    }
2647
2648    zend_hash_del(table, Z_STR(CONSTANT(opline->op1.constant)));
2649    zend_del_literal(CG(active_op_array), opline->op1.constant);
2650    zend_del_literal(CG(active_op_array), opline->op2.constant);
2651    MAKE_NOP(opline);
2652}
2653/* }}} */
2654
2655ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */
2656{
2657    if (op_array->early_binding != -1) {
2658        zend_bool orig_in_compilation = CG(in_compilation);
2659        uint32_t opline_num = op_array->early_binding;
2660        zend_class_entry *ce;
2661
2662        CG(in_compilation) = 1;
2663        while (opline_num != -1) {
2664            if ((ce = zend_lookup_class(Z_STR_P(op_array->opcodes[opline_num-1].op2.zv) TSRMLS_CC)) != NULL) {
2665                do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), ce, 0 TSRMLS_CC);
2666            }
2667            opline_num = op_array->opcodes[opline_num].result.opline_num;
2668        }
2669        CG(in_compilation) = orig_in_compilation;
2670    }
2671}
2672/* }}} */
2673
2674ZEND_API zend_string *zend_mangle_property_name(const char *src1, int src1_length, const char *src2, int src2_length, int internal) /* {{{ */
2675{
2676    zend_string *prop_name;
2677    int prop_name_length;
2678
2679    prop_name_length = 1 + src1_length + 1 + src2_length;
2680    prop_name = zend_string_alloc(prop_name_length, internal);
2681    prop_name->val[0] = '\0';
2682    memcpy(prop_name->val + 1, src1, src1_length+1);
2683    memcpy(prop_name->val + 1 + src1_length + 1, src2, src2_length+1);
2684    return prop_name;
2685}
2686/* }}} */
2687
2688static int zend_strnlen(const char* s, int maxlen) /* {{{ */
2689{
2690    int len = 0;
2691    while (*s++ && maxlen--) len++;
2692    return len;
2693}
2694/* }}} */
2695
2696ZEND_API int zend_unmangle_property_name_ex(const char *mangled_property, int len, const char **class_name, const char **prop_name, int *prop_len) /* {{{ */
2697{
2698    int class_name_len;
2699
2700    *class_name = NULL;
2701
2702    if (mangled_property[0]!=0) {
2703        *prop_name = mangled_property;
2704        if (prop_len) {
2705            *prop_len = len;
2706        }
2707        return SUCCESS;
2708    }
2709    if (len < 3 || mangled_property[1]==0) {
2710        zend_error(E_NOTICE, "Illegal member variable name");
2711        *prop_name = mangled_property;
2712        if (prop_len) {
2713            *prop_len = len;
2714        }
2715        return FAILURE;
2716    }
2717
2718    class_name_len = zend_strnlen(mangled_property + 1, --len - 1) + 1;
2719    if (class_name_len >= len || mangled_property[class_name_len]!=0) {
2720        zend_error(E_NOTICE, "Corrupt member variable name");
2721        *prop_name = mangled_property;
2722        if (prop_len) {
2723            *prop_len = len + 1;
2724        }
2725        return FAILURE;
2726    }
2727    *class_name = mangled_property + 1;
2728    *prop_name = (*class_name) + class_name_len;
2729    if (prop_len) {
2730        *prop_len = len - class_name_len;
2731    }
2732    return SUCCESS;
2733}
2734/* }}} */
2735
2736static zend_constant *zend_get_ct_const(zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
2737{
2738    zend_constant *c = NULL;
2739    char *lookup_name;
2740
2741    if (name->val[0] == '\\') {
2742        c = zend_hash_str_find_ptr(EG(zend_constants), name->val + 1, name->len - 1);
2743        if (!c) {
2744            lookup_name = zend_str_tolower_dup(name->val + 1, name->len - 1);
2745            c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len - 1);
2746            efree(lookup_name);
2747
2748            if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
2749                return c;
2750            }
2751            return NULL;
2752        }
2753    } else if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
2754        lookup_name = zend_str_tolower_dup(name->val, name->len);
2755        c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len);
2756        efree(lookup_name);
2757
2758        if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
2759            return c;
2760        }
2761        return NULL;
2762    }
2763
2764    if (c->flags & CONST_CT_SUBST) {
2765        return c;
2766    }
2767    if (all_internal_constants_substitution &&
2768        (c->flags & CONST_PERSISTENT) &&
2769        !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) &&
2770        !Z_CONSTANT(c->value)) {
2771        return c;
2772    }
2773    return NULL;
2774}
2775/* }}} */
2776
2777static int zend_constant_ct_subst(znode *result, zval *const_name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
2778{
2779    zend_constant *c = zend_get_ct_const(Z_STR_P(const_name),
2780        all_internal_constants_substitution TSRMLS_CC);
2781
2782    if (c) {
2783        result->op_type = IS_CONST;
2784        ZVAL_DUP(&result->u.constant, &c->value);
2785        return 1;
2786    }
2787    return 0;
2788}
2789/* }}} */
2790
2791void zend_init_list(void *result, void *item TSRMLS_DC) /* {{{ */
2792{
2793    void** list = emalloc(sizeof(void*) * 2);
2794
2795    list[0] = item;
2796    list[1] = NULL;
2797
2798    *(void**)result = list;
2799}
2800/* }}} */
2801
2802void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
2803{
2804    void** list = *(void**)result;
2805    size_t n = 0;
2806
2807    if (list) {
2808        while (list[n]) {
2809            n++;
2810        }
2811    }
2812
2813    list = erealloc(list, sizeof(void*) * (n+2));
2814
2815    list[n]   = item;
2816    list[n+1] = NULL;
2817
2818    *(void**)result = list;
2819}
2820/* }}} */
2821
2822void zend_do_extended_info(TSRMLS_D) /* {{{ */
2823{
2824    zend_op *opline;
2825
2826    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2827        return;
2828    }
2829
2830    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2831
2832    opline->opcode = ZEND_EXT_STMT;
2833    SET_UNUSED(opline->op1);
2834    SET_UNUSED(opline->op2);
2835}
2836/* }}} */
2837
2838void zend_do_extended_fcall_begin(TSRMLS_D) /* {{{ */
2839{
2840    zend_op *opline;
2841
2842    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2843        return;
2844    }
2845
2846    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2847
2848    opline->opcode = ZEND_EXT_FCALL_BEGIN;
2849    SET_UNUSED(opline->op1);
2850    SET_UNUSED(opline->op2);
2851}
2852/* }}} */
2853
2854void zend_do_extended_fcall_end(TSRMLS_D) /* {{{ */
2855{
2856    zend_op *opline;
2857
2858    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2859        return;
2860    }
2861
2862    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2863
2864    opline->opcode = ZEND_EXT_FCALL_END;
2865    SET_UNUSED(opline->op1);
2866    SET_UNUSED(opline->op2);
2867}
2868/* }}} */
2869
2870zend_bool zend_is_auto_global(zend_string *name TSRMLS_DC) /* {{{ */
2871{
2872    zend_auto_global *auto_global;
2873
2874    if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
2875        if (auto_global->armed) {
2876            auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC);
2877        }
2878        return 1;
2879    }
2880    return 0;
2881}
2882/* }}} */
2883
2884int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global_callback auto_global_callback TSRMLS_DC) /* {{{ */
2885{
2886    zend_auto_global auto_global;
2887    int retval;
2888
2889    auto_global.name = zend_new_interned_string(name TSRMLS_CC);
2890    auto_global.auto_global_callback = auto_global_callback;
2891    auto_global.jit = jit;
2892
2893    retval = zend_hash_add_mem(CG(auto_globals), name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE;
2894
2895    zend_string_release(auto_global.name);
2896    return retval;
2897}
2898/* }}} */
2899
2900ZEND_API void zend_activate_auto_globals(TSRMLS_D) /* {{{ */
2901{
2902    zend_auto_global *auto_global;
2903
2904    ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) {
2905        if (auto_global->jit) {
2906            auto_global->armed = 1;
2907        } else if (auto_global->auto_global_callback) {
2908            auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC);
2909        } else {
2910            auto_global->armed = 0;
2911        }
2912    } ZEND_HASH_FOREACH_END();
2913}
2914/* }}} */
2915
2916int zendlex(zend_parser_stack_elem *elem TSRMLS_DC) /* {{{ */
2917{
2918    zval zv;
2919    int retval;
2920
2921    if (CG(increment_lineno)) {
2922        CG(zend_lineno)++;
2923        CG(increment_lineno) = 0;
2924    }
2925
2926again:
2927    ZVAL_UNDEF(&zv);
2928    retval = lex_scan(&zv TSRMLS_CC);
2929    switch (retval) {
2930        case T_COMMENT:
2931        case T_DOC_COMMENT:
2932        case T_OPEN_TAG:
2933        case T_WHITESPACE:
2934            goto again;
2935
2936        case T_CLOSE_TAG:
2937            if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') {
2938                CG(increment_lineno) = 1;
2939            }
2940            if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
2941                goto again;
2942            }
2943            retval = ';'; /* implicit ; */
2944            break;
2945        case T_OPEN_TAG_WITH_ECHO:
2946            retval = T_ECHO;
2947            break;
2948    }
2949    if (Z_TYPE(zv) != IS_UNDEF) {
2950        elem->ast = zend_ast_create_zval(&zv);
2951    }
2952
2953    return retval;
2954}
2955/* }}} */
2956
2957ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC) /* {{{ */
2958{
2959    zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
2960    dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR);
2961
2962    ce->refcount = 1;
2963    ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED;
2964
2965    ce->default_properties_table = NULL;
2966    ce->default_static_members_table = NULL;
2967    zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0);
2968    zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
2969    zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
2970
2971    if (ce->type == ZEND_INTERNAL_CLASS) {
2972#ifdef ZTS
2973        int n = zend_hash_num_elements(CG(class_table));
2974
2975        if (CG(static_members_table) && n >= CG(last_static_member)) {
2976            /* Support for run-time declaration: dl() */
2977            CG(last_static_member) = n+1;
2978            CG(static_members_table) = realloc(CG(static_members_table), (n+1)*sizeof(zval*));
2979            CG(static_members_table)[n] = NULL;
2980        }
2981        ce->static_members_table = (zval*)(zend_intptr_t)n;
2982#else
2983        ce->static_members_table = NULL;
2984#endif
2985    } else {
2986        ce->static_members_table = ce->default_static_members_table;
2987        ce->info.user.doc_comment = NULL;
2988    }
2989
2990    ce->default_properties_count = 0;
2991    ce->default_static_members_count = 0;
2992
2993    if (nullify_handlers) {
2994        ce->constructor = NULL;
2995        ce->destructor = NULL;
2996        ce->clone = NULL;
2997        ce->__get = NULL;
2998        ce->__set = NULL;
2999        ce->__unset = NULL;
3000        ce->__isset = NULL;
3001        ce->__call = NULL;
3002        ce->__callstatic = NULL;
3003        ce->__tostring = NULL;
3004        ce->create_object = NULL;
3005        ce->get_iterator = NULL;
3006        ce->iterator_funcs.funcs = NULL;
3007        ce->interface_gets_implemented = NULL;
3008        ce->get_static_method = NULL;
3009        ce->parent = NULL;
3010        ce->num_interfaces = 0;
3011        ce->interfaces = NULL;
3012        ce->num_traits = 0;
3013        ce->traits = NULL;
3014        ce->trait_aliases = NULL;
3015        ce->trait_precedences = NULL;
3016        ce->serialize = NULL;
3017        ce->unserialize = NULL;
3018        ce->serialize_func = NULL;
3019        ce->unserialize_func = NULL;
3020        ce->__debugInfo = NULL;
3021        if (ce->type == ZEND_INTERNAL_CLASS) {
3022            ce->info.internal.module = NULL;
3023            ce->info.internal.builtin_functions = NULL;
3024        }
3025    }
3026}
3027/* }}} */
3028
3029uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
3030{
3031    if (zend_string_equals_literal_ci(name, "self")) {
3032        return ZEND_FETCH_CLASS_SELF;
3033    } else if (zend_string_equals_literal_ci(name, "parent")) {
3034        return ZEND_FETCH_CLASS_PARENT;
3035    } else if (zend_string_equals_literal_ci(name, "static")) {
3036        return ZEND_FETCH_CLASS_STATIC;
3037    } else {
3038        return ZEND_FETCH_CLASS_DEFAULT;
3039    }
3040}
3041/* }}} */
3042
3043ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
3044{
3045    return op_array->vars[EX_VAR_TO_NUM(var)];
3046}
3047/* }}} */
3048
3049zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
3050{
3051    zval *left_zv = zend_ast_get_zval(left_ast);
3052    zend_string *left = Z_STR_P(left_zv);
3053    zend_string *right = zend_ast_get_str(right_ast);
3054
3055    zend_string *result;
3056    size_t left_len = left->len;
3057    size_t len = left_len + right->len + 1; /* left\right */
3058
3059    result = zend_string_realloc(left, len, 0);
3060    result->val[left_len] = '\\';
3061    memcpy(&result->val[left_len + 1], right->val, right->len);
3062    result->val[len] = '\0';
3063    zend_string_release(right);
3064
3065    ZVAL_STR(left_zv, result);
3066    return left_ast;
3067}
3068/* }}} */
3069
3070/* A hacky way that is used to store the doc comment for properties */
3071zend_ast *zend_ast_append_doc_comment(zend_ast *list TSRMLS_DC) /* {{{ */
3072{
3073    if (CG(doc_comment)) {
3074        list = zend_ast_list_add(list, zend_ast_create_zval_from_str(CG(doc_comment)));
3075        CG(doc_comment) = NULL;
3076    }
3077
3078    return list;
3079}
3080/* }}} */
3081
3082void zend_verify_namespace(TSRMLS_D) /* {{{ */
3083{
3084    if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
3085        zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}");
3086    }
3087}
3088/* }}} */
3089
3090static void zend_reset_import_tables(TSRMLS_D) /* {{{ */
3091{
3092    if (CG(current_import)) {
3093        zend_hash_destroy(CG(current_import));
3094        efree(CG(current_import));
3095        CG(current_import) = NULL;
3096    }
3097
3098    if (CG(current_import_function)) {
3099        zend_hash_destroy(CG(current_import_function));
3100        efree(CG(current_import_function));
3101        CG(current_import_function) = NULL;
3102    }
3103
3104    if (CG(current_import_const)) {
3105        zend_hash_destroy(CG(current_import_const));
3106        efree(CG(current_import_const));
3107        CG(current_import_const) = NULL;
3108    }
3109}
3110/* }}} */
3111
3112static void zend_end_namespace(TSRMLS_D) /* {{{ */ {
3113    CG(in_namespace) = 0;
3114    zend_reset_import_tables(TSRMLS_C);
3115    if (CG(current_namespace)) {
3116        zend_string_release(CG(current_namespace));
3117        CG(current_namespace) = NULL;
3118    }
3119}
3120/* }}} */
3121
3122void zend_do_end_compilation(TSRMLS_D) /* {{{ */
3123{
3124    CG(has_bracketed_namespaces) = 0;
3125    zend_end_namespace(TSRMLS_C);
3126}
3127/* }}} */
3128
3129/* {{{ zend_dirname
3130   Returns directory name component of path */
3131ZEND_API size_t zend_dirname(char *path, size_t len)
3132{
3133    register char *end = path + len - 1;
3134    unsigned int len_adjust = 0;
3135
3136#ifdef PHP_WIN32
3137    /* Note that on Win32 CWD is per drive (heritage from CP/M).
3138     * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
3139     */
3140    if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
3141        /* Skip over the drive spec (if any) so as not to change */
3142        path += 2;
3143        len_adjust += 2;
3144        if (2 == len) {
3145            /* Return "c:" on Win32 for dirname("c:").
3146             * It would be more consistent to return "c:."
3147             * but that would require making the string *longer*.
3148             */
3149            return len;
3150        }
3151    }
3152#elif defined(NETWARE)
3153    /*
3154     * Find the first occurrence of : from the left
3155     * move the path pointer to the position just after :
3156     * increment the len_adjust to the length of path till colon character(inclusive)
3157     * If there is no character beyond : simple return len
3158     */
3159    char *colonpos = NULL;
3160    colonpos = strchr(path, ':');
3161    if (colonpos != NULL) {
3162        len_adjust = ((colonpos - path) + 1);
3163        path += len_adjust;
3164        if (len_adjust == len) {
3165            return len;
3166        }
3167    }
3168#endif
3169
3170    if (len == 0) {
3171        /* Illegal use of this function */
3172        return 0;
3173    }
3174
3175    /* Strip trailing slashes */
3176    while (end >= path && IS_SLASH_P(end)) {
3177        end--;
3178    }
3179    if (end < path) {
3180        /* The path only contained slashes */
3181        path[0] = DEFAULT_SLASH;
3182        path[1] = '\0';
3183        return 1 + len_adjust;
3184    }
3185
3186    /* Strip filename */
3187    while (end >= path && !IS_SLASH_P(end)) {
3188        end--;
3189    }
3190    if (end < path) {
3191        /* No slash found, therefore return '.' */
3192#ifdef NETWARE
3193        if (len_adjust == 0) {
3194            path[0] = '.';
3195            path[1] = '\0';
3196            return 1; /* only one character */
3197        } else {
3198            path[0] = '\0';
3199            return len_adjust;
3200        }
3201#else
3202        path[0] = '.';
3203        path[1] = '\0';
3204        return 1 + len_adjust;
3205#endif
3206    }
3207
3208    /* Strip slashes which came before the file name */
3209    while (end >= path && IS_SLASH_P(end)) {
3210        end--;
3211    }
3212    if (end < path) {
3213        path[0] = DEFAULT_SLASH;
3214        path[1] = '\0';
3215        return 1 + len_adjust;
3216    }
3217    *(end+1) = '\0';
3218
3219    return (size_t)(end + 1 - path) + len_adjust;
3220}
3221/* }}} */
3222
3223static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */
3224{
3225    return str1->len == str2->len
3226        && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len);
3227}
3228/* }}} */
3229
3230static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
3231{
3232    switch (type & BP_VAR_MASK) {
3233        case BP_VAR_R:
3234            return;
3235        case BP_VAR_W:
3236            opline->opcode += 3;
3237            return;
3238        case BP_VAR_REF:
3239            opline->opcode += 3;
3240            opline->extended_value |= ZEND_FETCH_MAKE_REF;
3241            return;
3242        case BP_VAR_RW:
3243            opline->opcode += 6;
3244            return;
3245        case BP_VAR_IS:
3246            opline->opcode += 9;
3247            return;
3248        case BP_VAR_FUNC_ARG:
3249            opline->opcode += 12;
3250            opline->extended_value |= type >> BP_VAR_SHIFT;
3251            return;
3252        case BP_VAR_UNSET:
3253            opline->opcode += 15;
3254            return;
3255        EMPTY_SWITCH_DEFAULT_CASE()
3256    }
3257}
3258/* }}} */
3259
3260static inline void zend_make_var_result(znode *result, zend_op *opline TSRMLS_DC) /* {{{ */
3261{
3262    opline->result_type = IS_VAR;
3263    opline->result.var = get_temporary_variable(CG(active_op_array));
3264    GET_NODE(result, opline->result);
3265}
3266/* }}} */
3267
3268static inline void zend_make_tmp_result(znode *result, zend_op *opline TSRMLS_DC) /* {{{ */
3269{
3270    opline->result_type = IS_TMP_VAR;
3271    opline->result.var = get_temporary_variable(CG(active_op_array));
3272    GET_NODE(result, opline->result);
3273}
3274/* }}} */
3275
3276static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3277{
3278    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3279    opline->opcode = opcode;
3280
3281    if (op1 == NULL) {
3282        SET_UNUSED(opline->op1);
3283    } else {
3284        SET_NODE(opline->op1, op1);
3285    }
3286
3287    if (op2 == NULL) {
3288        SET_UNUSED(opline->op2);
3289    } else {
3290        SET_NODE(opline->op2, op2);
3291    }
3292
3293    if (result) {
3294        zend_make_var_result(result, opline TSRMLS_CC);
3295    }
3296    return opline;
3297}
3298/* }}} */
3299
3300static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3301{
3302    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3303    opline->opcode = opcode;
3304
3305    if (op1 == NULL) {
3306        SET_UNUSED(opline->op1);
3307    } else {
3308        SET_NODE(opline->op1, op1);
3309    }
3310
3311    if (op2 == NULL) {
3312        SET_UNUSED(opline->op2);
3313    } else {
3314        SET_NODE(opline->op2, op2);
3315    }
3316
3317    zend_make_tmp_result(result, opline TSRMLS_CC);
3318
3319    return opline;
3320}
3321/* }}} */
3322
3323static void zend_emit_tick(TSRMLS_D) /* {{{ */
3324{
3325    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3326
3327    opline->opcode = ZEND_TICKS;
3328    SET_UNUSED(opline->op1);
3329    SET_UNUSED(opline->op2);
3330    opline->extended_value = Z_LVAL(CG(declarables).ticks);
3331}
3332/* }}} */
3333
3334static inline zend_op *zend_emit_op_data(znode *value TSRMLS_DC) /* {{{ */
3335{
3336    return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL TSRMLS_CC);
3337}
3338/* }}} */
3339
3340static inline uint32_t zend_emit_jump(uint32_t opnum_target TSRMLS_DC) /* {{{ */
3341{
3342    uint32_t opnum = get_next_op_number(CG(active_op_array));
3343    zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC);
3344    opline->op1.opline_num = opnum_target;
3345    return opnum;
3346}
3347/* }}} */
3348
3349static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target TSRMLS_DC) /* {{{ */
3350{
3351    uint32_t opnum = get_next_op_number(CG(active_op_array));
3352    zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL TSRMLS_CC);
3353    opline->op2.opline_num = opnum_target;
3354    return opnum;
3355}
3356/* }}} */
3357
3358static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_target TSRMLS_DC) /* {{{ */
3359{
3360    zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
3361    switch (opline->opcode) {
3362        case ZEND_JMP:
3363            opline->op1.opline_num = opnum_target;
3364            break;
3365        case ZEND_JMPZ:
3366        case ZEND_JMPNZ:
3367        case ZEND_JMPZ_EX:
3368        case ZEND_JMPNZ_EX:
3369            opline->op2.opline_num = opnum_target;
3370            break;
3371        EMPTY_SWITCH_DEFAULT_CASE()
3372    }
3373}
3374/* }}} */
3375
3376static inline void zend_update_jump_target_to_next(uint32_t opnum_jump TSRMLS_DC) /* {{{ */
3377{
3378    zend_update_jump_target(opnum_jump, get_next_op_number(CG(active_op_array)) TSRMLS_CC);
3379}
3380/* }}} */
3381
3382static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3383{
3384    zend_op tmp_opline;
3385    init_op(&tmp_opline TSRMLS_CC);
3386    tmp_opline.opcode = opcode;
3387    SET_NODE(tmp_opline.op1, op1);
3388    SET_NODE(tmp_opline.op2, op2);
3389    if (result) {
3390        zend_make_var_result(result, &tmp_opline TSRMLS_CC);
3391    }
3392
3393    zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline);
3394    return zend_stack_top(&CG(delayed_oplines_stack));
3395}
3396/* }}} */
3397
3398static inline uint32_t zend_delayed_compile_begin(TSRMLS_D) /* {{{ */
3399{
3400    return zend_stack_count(&CG(delayed_oplines_stack));
3401}
3402/* }}} */
3403
3404static zend_op *zend_delayed_compile_end(uint32_t offset TSRMLS_DC) /* {{{ */
3405{
3406    zend_op *opline, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
3407    uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack));
3408
3409    ZEND_ASSERT(count > offset);
3410    for (i = offset; i < count; ++i) {
3411        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3412        memcpy(opline, &oplines[i], sizeof(zend_op));
3413    }
3414    CG(delayed_oplines_stack).top = offset;
3415    return opline;
3416}
3417/* }}} */
3418
3419void zend_emit_final_return(zval *zv TSRMLS_DC) /* {{{ */
3420{
3421    znode zn;
3422    zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
3423
3424    zn.op_type = IS_CONST;
3425    if (zv) {
3426        ZVAL_COPY_VALUE(&zn.u.constant, zv);
3427    } else {
3428        ZVAL_NULL(&zn.u.constant);
3429    }
3430
3431    zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL TSRMLS_CC);
3432}
3433/* }}} */
3434
3435static inline zend_bool zend_is_variable(zend_ast *ast) /* {{{ */
3436{
3437    return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM
3438        || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP
3439        || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL
3440        || ast->kind == ZEND_AST_STATIC_CALL;
3441}
3442/* }}} */
3443
3444static inline zend_bool zend_is_call(zend_ast *ast) /* {{{ */
3445{
3446    return ast->kind == ZEND_AST_CALL
3447        || ast->kind == ZEND_AST_METHOD_CALL
3448        || ast->kind == ZEND_AST_STATIC_CALL;
3449}
3450/* }}} */
3451
3452static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
3453{
3454    return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL;
3455}
3456/* }}} */
3457
3458static inline zend_bool zend_can_write_to_variable(zend_ast *ast) /* {{{ */
3459{
3460    while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) {
3461        ast = ast->child[0];
3462    }
3463
3464    return zend_is_variable(ast);
3465}
3466/* }}} */
3467
3468static inline zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) /* {{{ */
3469{
3470    zend_string *name;
3471
3472    if (name_ast->kind != ZEND_AST_ZVAL) {
3473        return 0;
3474    }
3475
3476    /* Fully qualified names are always default refs */
3477    if (!name_ast->attr) {
3478        return 1;
3479    }
3480
3481    name = zend_ast_get_str(name_ast);
3482    return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(name);
3483}
3484/* }}} */
3485
3486static inline void zend_handle_numeric_op(znode *node TSRMLS_DC) /* {{{ */
3487{
3488    if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) {
3489        zend_ulong index;
3490
3491        if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) {
3492            zval_ptr_dtor(&node->u.constant);
3493            ZVAL_LONG(&node->u.constant, index);
3494        }
3495    }
3496}
3497/* }}} */
3498
3499static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node TSRMLS_DC) /* {{{ */
3500{
3501    if (class_node->op_type == IS_CONST) {
3502        opline->op1_type = IS_CONST;
3503        opline->op1.constant = zend_add_class_name_literal(
3504            CG(active_op_array), Z_STR(class_node->u.constant) TSRMLS_CC);
3505    } else {
3506        SET_NODE(opline->op1, class_node);
3507    }
3508}
3509/* }}} */
3510
3511static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast TSRMLS_DC) /* {{{ */
3512{
3513    zend_op *opline;
3514    znode name_node;
3515    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
3516
3517    if (name_node.op_type == IS_CONST) {
3518        zend_string *name = Z_STR(name_node.u.constant);
3519        uint32_t fetch_type = zend_get_class_fetch_type(name);
3520
3521        opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, NULL TSRMLS_CC);
3522        opline->extended_value = fetch_type;
3523
3524        if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
3525            uint32_t type = name_ast->kind == ZEND_AST_ZVAL ? name_ast->attr : ZEND_NAME_FQ;
3526            opline->op2_type = IS_CONST;
3527            opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
3528                zend_resolve_class_name(name, type TSRMLS_CC) TSRMLS_CC);
3529        }
3530
3531        zend_string_release(name);
3532    } else {
3533        opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node TSRMLS_CC);
3534        opline->extended_value = ZEND_FETCH_CLASS_DEFAULT;
3535    }
3536
3537    return opline;
3538}
3539/* }}} */
3540
3541static int zend_try_compile_cv(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3542{
3543    zend_ast *name_ast = ast->child[0];
3544    if (name_ast->kind == ZEND_AST_ZVAL) {
3545        zend_string *name = zval_get_string(zend_ast_get_zval(name_ast));
3546
3547        if (zend_is_auto_global(name TSRMLS_CC)) {
3548            zend_string_release(name);
3549            return FAILURE;
3550        }
3551
3552        result->op_type = IS_CV;
3553        result->u.op.var = lookup_cv(CG(active_op_array), name TSRMLS_CC);
3554
3555        if (zend_string_equals_literal(name, "this")) {
3556            CG(active_op_array)->this_var = result->u.op.var;
3557        }
3558        return SUCCESS;
3559    }
3560
3561    return FAILURE;
3562}
3563/* }}} */
3564
3565static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3566{
3567    zend_ast *name_ast = ast->child[0];
3568    znode name_node;
3569    zend_op *opline;
3570
3571    /* there is a chance someone is accessing $this */
3572    if (ast->kind != ZEND_AST_ZVAL
3573        && CG(active_op_array)->scope && CG(active_op_array)->this_var == -1
3574    ) {
3575        zend_string *key = zend_string_init("this", sizeof("this") - 1, 0);
3576        CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), key TSRMLS_CC);
3577    }
3578
3579    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
3580
3581    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3582    opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL TSRMLS_CC);
3583
3584    opline->extended_value = ZEND_FETCH_LOCAL;
3585    if (name_node.op_type == IS_CONST) {
3586        if (zend_is_auto_global(Z_STR(name_node.u.constant) TSRMLS_CC)) {
3587            opline->extended_value = ZEND_FETCH_GLOBAL;
3588        }
3589    }
3590
3591    return opline;
3592}
3593/* }}} */
3594
3595static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3596{
3597    if (zend_try_compile_cv(result, ast TSRMLS_CC) == FAILURE) {
3598        zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type TSRMLS_CC);
3599        zend_adjust_for_fetch_type(opline, type);
3600    }
3601}
3602/* }}} */
3603
3604static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3605{
3606    if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
3607        zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL TSRMLS_CC);
3608        opline->result_type = IS_VAR;
3609        opline->result.var = opline->op1.var;
3610    }
3611}
3612/* }}} */
3613
3614void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC);
3615
3616static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3617{
3618    zend_ast *var_ast = ast->child[0];
3619    zend_ast *dim_ast = ast->child[1];
3620
3621    znode var_node, dim_node;
3622
3623    zend_delayed_compile_var(&var_node, var_ast, type TSRMLS_CC);
3624    zend_separate_if_call_and_write(&var_node, var_ast, type TSRMLS_CC);
3625
3626    if (dim_ast == NULL) {
3627        if (type == BP_VAR_R || type == BP_VAR_IS) {
3628            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
3629        }
3630        if (type == BP_VAR_UNSET) {
3631            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
3632        }
3633        dim_node.op_type = IS_UNUSED;
3634    } else {
3635        zend_compile_expr(&dim_node, dim_ast TSRMLS_CC);
3636        zend_handle_numeric_op(&dim_node TSRMLS_CC);
3637    }
3638
3639    return zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node TSRMLS_CC);
3640}
3641/* }}} */
3642
3643static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3644{
3645    uint32_t offset = zend_delayed_compile_begin(TSRMLS_C);
3646    zend_delayed_compile_dim(result, ast, type TSRMLS_CC);
3647    return zend_delayed_compile_end(offset TSRMLS_CC);
3648}
3649/* }}} */
3650
3651void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3652{
3653    zend_op *opline = zend_compile_dim_common(result, ast, type TSRMLS_CC);
3654    zend_adjust_for_fetch_type(opline, type);
3655}
3656/* }}} */
3657
3658static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
3659{
3660    if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
3661        zval *name = zend_ast_get_zval(ast->child[0]);
3662        return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
3663    }
3664
3665    return 0;
3666}
3667/* }}} */
3668
3669static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3670{
3671    zend_ast *obj_ast = ast->child[0];
3672    zend_ast *prop_ast = ast->child[1];
3673
3674    znode obj_node, prop_node;
3675    zend_op *opline;
3676
3677    if (is_this_fetch(obj_ast)) {
3678        obj_node.op_type = IS_UNUSED;
3679    } else {
3680        zend_delayed_compile_var(&obj_node, obj_ast, type TSRMLS_CC);
3681        zend_separate_if_call_and_write(&obj_node, obj_ast, type TSRMLS_CC);
3682    }
3683    zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
3684
3685    opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node TSRMLS_CC);
3686    if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
3687        zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
3688    }
3689
3690    return opline;
3691}
3692/* }}} */
3693
3694static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3695{
3696    uint32_t offset = zend_delayed_compile_begin(TSRMLS_C);
3697    zend_delayed_compile_prop(result, ast, type TSRMLS_CC);
3698    return zend_delayed_compile_end(offset TSRMLS_CC);
3699}
3700/* }}} */
3701
3702void zend_compile_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3703{
3704    zend_op *opline = zend_compile_prop_common(result, ast, type TSRMLS_CC);
3705    zend_adjust_for_fetch_type(opline, type);
3706}
3707/* }}} */
3708
3709zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3710{
3711    zend_ast *class_ast = ast->child[0];
3712    zend_ast *prop_ast = ast->child[1];
3713
3714    znode class_node, prop_node;
3715    zend_op *opline;
3716
3717    if (zend_is_const_default_class_ref(class_ast)) {
3718        class_node.op_type = IS_CONST;
3719        ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC));
3720    } else {
3721        zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
3722    }
3723
3724    zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
3725
3726    opline = zend_emit_op(result, ZEND_FETCH_R, &prop_node, NULL TSRMLS_CC);
3727    if (opline->op1_type == IS_CONST) {
3728        zend_alloc_polymorphic_cache_slot(opline->op1.constant TSRMLS_CC);
3729    }
3730    if (class_node.op_type == IS_CONST) {
3731        opline->op2_type = IS_CONST;
3732        opline->op2.constant = zend_add_class_name_literal(
3733            CG(active_op_array), Z_STR(class_node.u.constant) TSRMLS_CC);
3734    } else {
3735        SET_NODE(opline->op2, &class_node);
3736    }
3737    opline->extended_value |= ZEND_FETCH_STATIC_MEMBER;
3738
3739    return opline;
3740}
3741/* }}} */
3742
3743void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3744{
3745    zend_op *opline = zend_compile_static_prop_common(result, ast, type TSRMLS_CC);
3746    zend_adjust_for_fetch_type(opline, type);
3747}
3748/* }}} */
3749
3750static inline zend_uchar get_list_fetch_opcode(zend_uchar op_type) /* {{{ */
3751{
3752    switch (op_type) {
3753        case IS_VAR:
3754        case IS_CV:
3755            return ZEND_FETCH_DIM_R;
3756        case IS_TMP_VAR:
3757        case IS_CONST:
3758            return ZEND_FETCH_DIM_TMP_VAR;
3759        EMPTY_SWITCH_DEFAULT_CASE()
3760    }
3761}
3762/* }}} */
3763
3764static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node TSRMLS_DC) /* {{{ */
3765{
3766    zend_ast_list *list = zend_ast_get_list(ast);
3767    uint32_t i;
3768
3769    if (list->children == 1 && !list->child[0]) {
3770        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list");
3771    }
3772
3773    for (i = 0; i < list->children; ++i) {
3774        zend_ast *var_ast = list->child[i];
3775        znode fetch_result, dim_node, var_node, assign_result;
3776        zend_op *opline;
3777
3778        if (var_ast == NULL) {
3779            continue;
3780        }
3781
3782        dim_node.op_type = IS_CONST;
3783        ZVAL_LONG(&dim_node.u.constant, i);
3784
3785        if (expr_node->op_type == IS_CONST) {
3786            Z_TRY_ADDREF(expr_node->u.constant);
3787        }
3788
3789        opline = zend_emit_op(&fetch_result,
3790            get_list_fetch_opcode(expr_node->op_type), expr_node, &dim_node TSRMLS_CC);
3791        opline->extended_value |= ZEND_FETCH_ADD_LOCK;
3792
3793        if (var_ast->kind != ZEND_AST_LIST) {
3794            if (is_this_fetch(var_ast)) {
3795                zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3796            }
3797            zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC);
3798            zend_emit_op(&assign_result, ZEND_ASSIGN, &var_node, &fetch_result TSRMLS_CC);
3799            zend_do_free(&assign_result TSRMLS_CC);
3800        } else {
3801            zend_compile_list_assign(&assign_result, var_ast, &fetch_result TSRMLS_CC);
3802            zend_do_free(&assign_result TSRMLS_CC);
3803        }
3804    }
3805    *result = *expr_node;
3806}
3807/* }}} */
3808
3809void zend_ensure_writable_variable(const zend_ast *ast) /* {{{ */
3810{
3811    if (ast->kind == ZEND_AST_CALL) {
3812        zend_error_noreturn(E_COMPILE_ERROR, "Can't use function return value in write context");
3813    }
3814    if (ast->kind == ZEND_AST_METHOD_CALL || ast->kind == ZEND_AST_STATIC_CALL) {
3815        zend_error_noreturn(E_COMPILE_ERROR, "Can't use method return value in write context");
3816    }
3817}
3818/* }}} */
3819
3820/* Detects $a... = $a pattern */
3821zend_bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast TSRMLS_DC) /* {{{ */
3822{
3823    if (expr_ast->kind != ZEND_AST_VAR || expr_ast->child[0]->kind != ZEND_AST_ZVAL) {
3824        return 0;
3825    }
3826
3827    while (zend_is_variable(var_ast) && var_ast->kind != ZEND_AST_VAR) {
3828        var_ast = var_ast->child[0];
3829    }
3830
3831    if (var_ast->kind != ZEND_AST_VAR || var_ast->child[0]->kind != ZEND_AST_ZVAL) {
3832        return 0;
3833    }
3834
3835    {
3836        zend_string *name1 = zval_get_string(zend_ast_get_zval(var_ast->child[0]));
3837        zend_string *name2 = zval_get_string(zend_ast_get_zval(expr_ast->child[0]));
3838        zend_bool result = zend_string_equals(name1, name2);
3839        zend_string_release(name1);
3840        zend_string_release(name2);
3841        return result;
3842    }
3843}
3844/* }}} */
3845
3846void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3847{
3848    zend_ast *var_ast = ast->child[0];
3849    zend_ast *expr_ast = ast->child[1];
3850
3851    znode var_node, expr_node;
3852    zend_op *opline;
3853    uint32_t offset;
3854
3855    if (is_this_fetch(var_ast)) {
3856        zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3857    }
3858
3859    zend_ensure_writable_variable(var_ast);
3860
3861    switch (var_ast->kind) {
3862        case ZEND_AST_VAR:
3863        case ZEND_AST_STATIC_PROP:
3864            zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC);
3865            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3866            zend_emit_op(result, ZEND_ASSIGN, &var_node, &expr_node TSRMLS_CC);
3867            return;
3868        case ZEND_AST_DIM:
3869            offset = zend_delayed_compile_begin(TSRMLS_C);
3870            zend_delayed_compile_dim(result, var_ast, BP_VAR_W TSRMLS_CC);
3871
3872            if (zend_is_assign_to_self(var_ast, expr_ast TSRMLS_CC)) {
3873                /* $a[0] = $a should evaluate the right $a first */
3874                zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R TSRMLS_CC);
3875            } else {
3876                zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3877            }
3878
3879            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3880            opline->opcode = ZEND_ASSIGN_DIM;
3881
3882            opline = zend_emit_op_data(&expr_node TSRMLS_CC);
3883            opline->op2.var = get_temporary_variable(CG(active_op_array));
3884            opline->op2_type = IS_VAR;
3885            return;
3886        case ZEND_AST_PROP:
3887            offset = zend_delayed_compile_begin(TSRMLS_C);
3888            zend_delayed_compile_prop(result, var_ast, BP_VAR_W TSRMLS_CC);
3889            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3890
3891            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3892            opline->opcode = ZEND_ASSIGN_OBJ;
3893
3894            zend_emit_op_data(&expr_node TSRMLS_CC);
3895            return;
3896        case ZEND_AST_LIST:
3897            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3898            zend_compile_list_assign(result, var_ast, &expr_node TSRMLS_CC);
3899            return;
3900        EMPTY_SWITCH_DEFAULT_CASE();
3901    }
3902}
3903/* }}} */
3904
3905static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
3906{
3907    znode dummy_node;
3908    zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
3909        zend_ast_create_znode(value_node));
3910    zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC);
3911    zend_do_free(&dummy_node TSRMLS_CC);
3912}
3913/* }}} */
3914
3915void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3916{
3917    zend_ast *target_ast = ast->child[0];
3918    zend_ast *source_ast = ast->child[1];
3919
3920    znode target_node, source_node;
3921    zend_op *opline;
3922
3923    if (is_this_fetch(target_ast)) {
3924        zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3925    }
3926    zend_ensure_writable_variable(target_ast);
3927
3928    zend_compile_var(&target_node, target_ast, BP_VAR_W TSRMLS_CC);
3929    zend_compile_var(&source_node, source_ast, BP_VAR_REF TSRMLS_CC);
3930
3931    opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node TSRMLS_CC);
3932    if (!result) {
3933        opline->result_type |= EXT_TYPE_UNUSED;
3934    }
3935
3936    if (zend_is_call(source_ast)) {
3937        opline->extended_value = ZEND_RETURNS_FUNCTION;
3938    } else if (source_ast->kind == ZEND_AST_NEW) {
3939        zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated");
3940        opline->extended_value = ZEND_RETURNS_NEW;
3941    }
3942}
3943/* }}} */
3944
3945static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
3946{
3947    zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN_REF, var_ast,
3948        zend_ast_create_znode(value_node));
3949    zend_compile_assign_ref(NULL, assign_ast TSRMLS_CC);
3950}
3951/* }}} */
3952
3953void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3954{
3955    zend_ast *var_ast = ast->child[0];
3956    zend_ast *expr_ast = ast->child[1];
3957    uint32_t opcode = ast->attr;
3958
3959    znode var_node, expr_node;
3960    zend_op *opline;
3961    uint32_t offset;
3962
3963    zend_ensure_writable_variable(var_ast);
3964
3965    switch (var_ast->kind) {
3966        case ZEND_AST_VAR:
3967        case ZEND_AST_STATIC_PROP:
3968            zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
3969            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3970            zend_emit_op(result, opcode, &var_node, &expr_node TSRMLS_CC);
3971            return;
3972        case ZEND_AST_DIM:
3973            offset = zend_delayed_compile_begin(TSRMLS_C);
3974            zend_delayed_compile_dim(result, var_ast, BP_VAR_RW TSRMLS_CC);
3975            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3976
3977            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3978            opline->opcode = opcode;
3979            opline->extended_value = ZEND_ASSIGN_DIM;
3980
3981            opline = zend_emit_op_data(&expr_node TSRMLS_CC);
3982            opline->op2.var = get_temporary_variable(CG(active_op_array));
3983            opline->op2_type = IS_VAR;
3984            return;
3985        case ZEND_AST_PROP:
3986            offset = zend_delayed_compile_begin(TSRMLS_C);
3987            zend_delayed_compile_prop(result, var_ast, BP_VAR_RW TSRMLS_CC);
3988            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3989
3990            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3991            opline->opcode = opcode;
3992            opline->extended_value = ZEND_ASSIGN_OBJ;
3993
3994            zend_emit_op_data(&expr_node TSRMLS_CC);
3995            return;
3996        EMPTY_SWITCH_DEFAULT_CASE()
3997    }
3998}
3999/* }}} */
4000
4001uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc TSRMLS_DC) /* {{{ */
4002{
4003    /* TODO.AST &var error */
4004    zend_ast_list *args = zend_ast_get_list(ast);
4005    uint32_t i;
4006    zend_bool uses_arg_unpack = 0;
4007    uint32_t arg_count = 0; /* number of arguments not including unpacks */
4008
4009    for (i = 0; i < args->children; ++i) {
4010        zend_ast *arg = args->child[i];
4011        uint32_t arg_num = i + 1;
4012
4013        znode arg_node;
4014        zend_op *opline;
4015        zend_uchar opcode;
4016        zend_ulong flags = 0;
4017
4018        if (arg->kind == ZEND_AST_UNPACK) {
4019            uses_arg_unpack = 1;
4020            fbc = NULL;
4021
4022            zend_compile_expr(&arg_node, arg->child[0] TSRMLS_CC);
4023            opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL TSRMLS_CC);
4024            opline->op2.num = arg_count;
4025            continue;
4026        }
4027
4028        if (uses_arg_unpack) {
4029            zend_error_noreturn(E_COMPILE_ERROR,
4030                "Cannot use positional argument after argument unpacking");
4031        }
4032
4033        arg_count++;
4034        if (zend_is_variable(arg)) {
4035            if (zend_is_call(arg)) {
4036                zend_compile_var(&arg_node, arg, BP_VAR_R TSRMLS_CC);
4037                if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
4038                    /* Function call was converted into builtin instruction */
4039                    opcode = ZEND_SEND_VAL;
4040                } else {
4041                    opcode = ZEND_SEND_VAR_NO_REF;
4042                    flags |= ZEND_ARG_SEND_FUNCTION;
4043                    if (fbc && ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
4044                        flags |= ZEND_ARG_SEND_BY_REF;
4045                        if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
4046                            flags |= ZEND_ARG_SEND_SILENT;
4047                        }
4048                    }
4049                }
4050            } else if (fbc) {
4051                if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
4052                    zend_compile_var(&arg_node, arg, BP_VAR_W TSRMLS_CC);
4053                    opcode = ZEND_SEND_REF;
4054                } else {
4055                    zend_compile_var(&arg_node, arg, BP_VAR_R TSRMLS_CC);
4056                    opcode = ZEND_SEND_VAR;
4057                }
4058            } else {
4059                zend_compile_var(&arg_node, arg,
4060                    BP_VAR_FUNC_ARG | (arg_num << BP_VAR_SHIFT) TSRMLS_CC);
4061                opcode = ZEND_SEND_VAR_EX;
4062            }
4063        } else {
4064            zend_compile_expr(&arg_node, arg TSRMLS_CC);
4065            if (arg_node.op_type & (IS_VAR|IS_CV)) {
4066                opcode = ZEND_SEND_VAR_NO_REF;
4067                if (fbc && ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
4068                    flags |= ZEND_ARG_SEND_BY_REF;
4069                }
4070            } else {
4071                if (fbc) {
4072                    opcode = ZEND_SEND_VAL;
4073                    if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
4074                        zend_error_noreturn(E_COMPILE_ERROR, "Only variables can be passed by reference");
4075                    }
4076                } else {
4077                    opcode = ZEND_SEND_VAL_EX;
4078                }
4079            }
4080        }
4081
4082        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4083        opline->opcode = opcode;
4084        SET_NODE(opline->op1, &arg_node);
4085        SET_UNUSED(opline->op2);
4086        opline->op2.opline_num = arg_num;
4087
4088        if (opcode == ZEND_SEND_VAR_NO_REF) {
4089            if (fbc) {
4090                flags |= ZEND_ARG_COMPILE_TIME_BOUND;
4091            }
4092            opline->extended_value = flags;
4093        } else if (fbc) {
4094            opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
4095        }
4096    }
4097
4098    return arg_count;
4099}
4100/* }}} */
4101
4102void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc TSRMLS_DC) /* {{{ */
4103{
4104    zend_op *opline;
4105    uint32_t opnum_init = get_next_op_number(CG(active_op_array)) - 1;
4106    uint32_t arg_count;
4107    uint32_t call_flags;
4108
4109    zend_do_extended_fcall_begin(TSRMLS_C);
4110
4111    arg_count = zend_compile_args(args_ast, fbc TSRMLS_CC);
4112
4113    opline = &CG(active_op_array)->opcodes[opnum_init];
4114    opline->extended_value = arg_count;
4115
4116    call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0);
4117    opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4118    opline->op1.num = call_flags;
4119
4120    zend_do_extended_fcall_end(TSRMLS_C);
4121}
4122/* }}} */
4123
4124zend_bool zend_compile_function_name(znode *name_node, zend_ast *name_ast TSRMLS_DC) /* {{{ */
4125{
4126    zend_string *orig_name = zend_ast_get_str(name_ast);
4127    zend_bool is_fully_qualified;
4128
4129    name_node->op_type = IS_CONST;
4130    ZVAL_STR(&name_node->u.constant, zend_resolve_function_name(
4131        orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC));
4132
4133    return !is_fully_qualified && CG(current_namespace);
4134}
4135/* }}} */
4136
4137void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast TSRMLS_DC) /* {{{ */
4138{
4139    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4140    opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
4141    SET_UNUSED(opline->op1);
4142    opline->op2_type = IS_CONST;
4143    opline->op2.constant = zend_add_ns_func_name_literal(
4144        CG(active_op_array), &name_node->u.constant TSRMLS_CC);
4145    zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4146
4147    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4148}
4149/* }}} */
4150
4151void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast TSRMLS_DC) /* {{{ */
4152{
4153    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4154    opline->opcode = ZEND_INIT_FCALL_BY_NAME;
4155    SET_UNUSED(opline->op1);
4156    if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
4157        opline->op2_type = IS_CONST;
4158        opline->op2.constant
4159            = zend_add_func_name_literal(CG(active_op_array), &name_node->u.constant TSRMLS_CC);
4160        zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4161    } else {
4162        SET_NODE(opline->op2, name_node);
4163    }
4164
4165    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4166}
4167/* }}} */
4168
4169static zend_bool zend_args_contain_unpack(zend_ast_list *args) /* {{{ */
4170{
4171    uint32_t i;
4172    for (i = 0; i < args->children; ++i) {
4173        if (args->child[i]->kind == ZEND_AST_UNPACK) {
4174            return 1;
4175        }
4176    }
4177    return 0;
4178}
4179/* }}} */
4180
4181int zend_compile_func_strlen(znode *result, zend_ast_list *args TSRMLS_DC) /* {{{ */
4182{
4183    znode arg_node;
4184
4185    if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)
4186        || args->children != 1 || args->child[0]->kind == ZEND_AST_UNPACK
4187    ) {
4188        return FAILURE;
4189    }
4190
4191    zend_compile_expr(&arg_node, args->child[0] TSRMLS_CC);
4192    zend_emit_op_tmp(result, ZEND_STRLEN, &arg_node, NULL TSRMLS_CC);
4193    return SUCCESS;
4194}
4195/* }}} */
4196
4197int zend_compile_func_typecheck(znode *result, zend_ast_list *args, uint32_t type TSRMLS_DC) /* {{{ */
4198{
4199    znode arg_node;
4200    zend_op *opline;
4201
4202    if (args->children != 1 || args->child[0]->kind == ZEND_AST_UNPACK) {
4203        return FAILURE;
4204    }
4205
4206    zend_compile_expr(&arg_node, args->child[0] TSRMLS_CC);
4207    opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL TSRMLS_CC);
4208    opline->extended_value = type;
4209    return SUCCESS;
4210}
4211/* }}} */
4212
4213int zend_compile_func_defined(znode *result, zend_ast_list *args TSRMLS_DC) /* {{{ */
4214{
4215    zend_string *name;
4216    zend_op *opline;
4217
4218    if (args->children != 1 || args->child[0]->kind != ZEND_AST_ZVAL) {
4219        return FAILURE;
4220    }
4221
4222    name = zval_get_string(zend_ast_get_zval(args->child[0]));
4223    if (zend_memrchr(name->val, '\\', name->len) || zend_memrchr(name->val, ':', name->len)) {
4224        zend_string_release(name);
4225        return FAILURE;
4226    }
4227
4228    opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL TSRMLS_CC);
4229    opline->op1_type = IS_CONST;
4230    LITERAL_STR(opline->op1, name);
4231    zend_alloc_cache_slot(opline->op1.constant TSRMLS_CC);
4232
4233    /* Lowercase constant name in a separate literal */
4234    {
4235        zval c;
4236        zend_string *lcname = zend_string_alloc(name->len, 0);
4237        zend_str_tolower_copy(lcname->val, name->val, name->len);
4238        ZVAL_NEW_STR(&c, lcname);
4239        zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
4240    }
4241    return SUCCESS;
4242}
4243/* }}} */
4244
4245static int zend_try_compile_ct_bound_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args TSRMLS_DC) /* {{{ */
4246{
4247    zend_string *name, *lcname;
4248    zend_function *fbc;
4249    zend_op *opline;
4250
4251    if (name_ast->kind != ZEND_AST_CONST || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
4252        return FAILURE;
4253    }
4254
4255    name = zend_ast_get_str(name_ast);
4256    lcname = zend_string_alloc(name->len, 0);
4257    zend_str_tolower_copy(lcname->val, name->val, name->len);
4258
4259    fbc = zend_hash_find_ptr(CG(function_table), lcname);
4260    if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION &&
4261        (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
4262    ) {
4263        zend_string_free(lcname);
4264        return FAILURE;
4265    }
4266
4267    opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, NULL TSRMLS_CC);
4268    opline->op2_type = IS_CONST;
4269    LITERAL_STR(opline->op2, lcname);
4270    opline->extended_value = num_args;
4271
4272    return SUCCESS;
4273}
4274/* }}} */
4275
4276static void zend_compile_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name TSRMLS_DC) /* {{{ */
4277{
4278    zend_op *opline;
4279    znode name_node;
4280
4281    if (zend_try_compile_ct_bound_init_user_func(result, name_ast, num_args TSRMLS_CC) == SUCCESS) {
4282        return;
4283    }
4284
4285    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4286
4287    opline = zend_emit_op(NULL, ZEND_INIT_USER_CALL, NULL, &name_node TSRMLS_CC);
4288    opline->op1_type = IS_CONST;
4289    LITERAL_STR(opline->op1, zend_string_copy(orig_func_name));
4290    opline->extended_value = num_args;
4291}
4292/* }}} */
4293
4294/* cufa = call_user_func_array */
4295int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcname TSRMLS_DC) /* {{{ */
4296{
4297    znode arg_node;
4298
4299    if (args->children != 2 || zend_args_contain_unpack(args)) {
4300        return FAILURE;
4301    }
4302
4303    zend_compile_init_user_func(NULL, args->child[0], 1, lcname TSRMLS_CC);
4304    zend_compile_expr(&arg_node, args->child[1] TSRMLS_CC);
4305    zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL TSRMLS_CC);
4306    zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4307
4308    return SUCCESS;
4309}
4310/* }}} */
4311
4312/* cuf = call_user_func */
4313int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname TSRMLS_DC) /* {{{ */
4314{
4315    uint32_t i;
4316
4317    if (args->children < 1 || zend_args_contain_unpack(args)) {
4318        return FAILURE;
4319    }
4320
4321    zend_compile_init_user_func(NULL, args->child[0], args->children - 1, lcname TSRMLS_CC);
4322    for (i = 1; i < args->children; ++i) {
4323        zend_ast *arg_ast = args->child[i];
4324        znode arg_node;
4325        zend_op *opline;
4326        zend_bool send_user = 0;
4327
4328        if (zend_is_variable(arg_ast) && !zend_is_call(arg_ast)) {
4329            zend_compile_var(&arg_node, arg_ast, BP_VAR_FUNC_ARG | (i << BP_VAR_SHIFT) TSRMLS_CC);
4330            send_user = 1;
4331        } else {
4332            zend_compile_expr(&arg_node, arg_ast TSRMLS_CC);
4333            if (arg_node.op_type & (IS_VAR|IS_CV)) {
4334                send_user = 1;
4335            }
4336        }
4337
4338        if (send_user) {
4339            opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL TSRMLS_CC);
4340        } else {
4341            opline = zend_emit_op(NULL, ZEND_SEND_VAL, &arg_node, NULL TSRMLS_CC);
4342        }
4343
4344        opline->op2.opline_num = i;
4345    }
4346    zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4347
4348    return SUCCESS;
4349}
4350/* }}} */
4351
4352int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args TSRMLS_DC) /* {{{ */
4353{
4354    if (zend_string_equals_literal(lcname, "strlen")) {
4355        return zend_compile_func_strlen(result, args TSRMLS_CC);
4356    } else if (zend_string_equals_literal(lcname, "is_null")) {
4357        return zend_compile_func_typecheck(result, args, IS_NULL TSRMLS_CC);
4358    } else if (zend_string_equals_literal(lcname, "is_bool")) {
4359        return zend_compile_func_typecheck(result, args, _IS_BOOL TSRMLS_CC);
4360    } else if (zend_string_equals_literal(lcname, "is_long")
4361        || zend_string_equals_literal(lcname, "is_int")
4362        || zend_string_equals_literal(lcname, "is_integer")
4363    ) {
4364        return zend_compile_func_typecheck(result, args, IS_LONG TSRMLS_CC);
4365    } else if (zend_string_equals_literal(lcname, "is_float")
4366        || zend_string_equals_literal(lcname, "is_double")
4367        || zend_string_equals_literal(lcname, "is_real")
4368    ) {
4369        return zend_compile_func_typecheck(result, args, IS_DOUBLE TSRMLS_CC);
4370    } else if (zend_string_equals_literal(lcname, "is_string")) {
4371        return zend_compile_func_typecheck(result, args, IS_STRING TSRMLS_CC);
4372    } else if (zend_string_equals_literal(lcname, "is_array")) {
4373        return zend_compile_func_typecheck(result, args, IS_ARRAY TSRMLS_CC);
4374    } else if (zend_string_equals_literal(lcname, "is_object")) {
4375        return zend_compile_func_typecheck(result, args, IS_OBJECT TSRMLS_CC);
4376    } else if (zend_string_equals_literal(lcname, "is_resource")) {
4377        return zend_compile_func_typecheck(result, args, IS_RESOURCE TSRMLS_CC);
4378    } else if (zend_string_equals_literal(lcname, "defined")) {
4379        return zend_compile_func_defined(result, args TSRMLS_CC);
4380    } else if (zend_string_equals_literal(lcname, "call_user_func_array")) {
4381        return zend_compile_func_cufa(result, args, lcname TSRMLS_CC);
4382    } else if (zend_string_equals_literal(lcname, "call_user_func")) {
4383        return zend_compile_func_cuf(result, args, lcname TSRMLS_CC);
4384    } else {
4385        return FAILURE;
4386    }
4387}
4388/* }}} */
4389
4390void zend_compile_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4391{
4392    zend_ast *name_ast = ast->child[0];
4393    zend_ast *args_ast = ast->child[1];
4394
4395    znode name_node;
4396
4397    if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
4398        zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4399        zend_compile_dynamic_call(result, &name_node, args_ast TSRMLS_CC);
4400        return;
4401    }
4402
4403    {
4404        zend_bool runtime_resolution = zend_compile_function_name(&name_node, name_ast TSRMLS_CC);
4405        if (runtime_resolution) {
4406            zend_compile_ns_call(result, &name_node, args_ast TSRMLS_CC);
4407            return;
4408        }
4409    }
4410
4411    {
4412        zval *name = &name_node.u.constant;
4413        zend_string *lcname = zend_string_alloc(Z_STRLEN_P(name), 0);
4414        zend_function *fbc;
4415        zend_op *opline;
4416
4417        zend_str_tolower_copy(lcname->val, Z_STRVAL_P(name), Z_STRLEN_P(name));
4418
4419        fbc = zend_hash_find_ptr(CG(function_table), lcname);
4420        if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION &&
4421            (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
4422        ) {
4423            zend_string_release(lcname);
4424            zend_compile_dynamic_call(result, &name_node, args_ast TSRMLS_CC);
4425            return;
4426        }
4427
4428        if (zend_try_compile_special_func(result, lcname,
4429                zend_ast_get_list(args_ast) TSRMLS_CC) == SUCCESS
4430        ) {
4431            zend_string_release(lcname);
4432            zval_ptr_dtor(&name_node.u.constant);
4433            return;
4434        }
4435
4436        zval_ptr_dtor(&name_node.u.constant);
4437        ZVAL_NEW_STR(&name_node.u.constant, lcname);
4438
4439        opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node TSRMLS_CC);
4440        zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4441
4442        zend_compile_call_common(result, args_ast, fbc TSRMLS_CC);
4443    }
4444}
4445/* }}} */
4446
4447void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4448{
4449    zend_ast *obj_ast = ast->child[0];
4450    zend_ast *method_ast = ast->child[1];
4451    zend_ast *args_ast = ast->child[2];
4452
4453    znode obj_node, method_node;
4454    zend_op *opline;
4455
4456    if (is_this_fetch(obj_ast)) {
4457        obj_node.op_type = IS_UNUSED;
4458    } else {
4459        zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
4460    }
4461
4462    zend_compile_expr(&method_node, method_ast TSRMLS_CC);
4463    opline = zend_emit_op(NULL, ZEND_INIT_METHOD_CALL, &obj_node, NULL TSRMLS_CC);
4464
4465    if (method_node.op_type == IS_CONST) {
4466        if (Z_TYPE(method_node.u.constant) != IS_STRING) {
4467            zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
4468        }
4469
4470        opline->op2_type = IS_CONST;
4471        opline->op2.constant =
4472            zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
4473        zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
4474    } else {
4475        SET_NODE(opline->op2, &method_node);
4476    }
4477
4478    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4479}
4480/* }}} */
4481
4482zend_bool zend_is_constructor(zend_string *name) /* {{{ */
4483{
4484    return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
4485}
4486/* }}} */
4487
4488void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4489{
4490    zend_ast *class_ast = ast->child[0];
4491    zend_ast *method_ast = ast->child[1];
4492    zend_ast *args_ast = ast->child[2];
4493
4494    znode class_node, method_node;
4495    zend_op *opline;
4496    zend_ulong extended_value = 0;
4497
4498    if (zend_is_const_default_class_ref(class_ast)) {
4499        class_node.op_type = IS_CONST;
4500        ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC));
4501    } else {
4502        opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
4503        extended_value = opline->extended_value;
4504    }
4505
4506    zend_compile_expr(&method_node, method_ast TSRMLS_CC);
4507    if (method_node.op_type == IS_CONST) {
4508        zval *name = &method_node.u.constant;
4509        if (Z_TYPE_P(name) != IS_STRING) {
4510            zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
4511        }
4512        if (zend_is_constructor(Z_STR_P(name))) {
4513            zval_ptr_dtor(name);
4514            method_node.op_type = IS_UNUSED;
4515        }
4516    }
4517
4518    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4519    opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
4520    opline->extended_value = extended_value;
4521
4522    zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
4523
4524    if (method_node.op_type == IS_CONST) {
4525        opline->op2_type = IS_CONST;
4526        opline->op2.constant =
4527            zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
4528        if (opline->op1_type == IS_CONST) {
4529            zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4530        } else {
4531            zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
4532        }
4533    } else {
4534        SET_NODE(opline->op2, &method_node);
4535    }
4536
4537    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4538}
4539/* }}} */
4540
4541void zend_compile_new(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
4542{
4543    zend_ast *class_ast = ast->child[0];
4544    zend_ast *args_ast = ast->child[1];
4545
4546    znode class_node, ctor_result;
4547    zend_op *opline;
4548    uint32_t opnum;
4549
4550    zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
4551
4552    opnum = get_next_op_number(CG(active_op_array));
4553    opline = zend_emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC);
4554
4555    zend_compile_call_common(&ctor_result, args_ast, NULL TSRMLS_CC);
4556    zend_do_free(&ctor_result TSRMLS_CC);
4557
4558    /* New jumps over ctor call if ctor does not exist */
4559    opline = &CG(active_op_array)->opcodes[opnum];
4560    opline->op2.opline_num = get_next_op_number(CG(active_op_array));
4561}
4562/* }}} */
4563
4564void zend_compile_clone(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
4565{
4566    zend_ast *obj_ast = ast->child[0];
4567
4568    znode obj_node;
4569    zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
4570
4571    zend_emit_op(result, ZEND_CLONE, &obj_node, NULL TSRMLS_CC);
4572}
4573/* }}} */
4574
4575void zend_compile_global_var(zend_ast *ast TSRMLS_DC) /* {{{ */
4576{
4577    zend_ast *var_ast = ast->child[0];
4578    zend_ast *name_ast = var_ast->child[0];
4579
4580    znode name_node, result;
4581
4582    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4583    if (name_node.op_type == IS_CONST) {
4584        if (Z_TYPE(name_node.u.constant) != IS_STRING) {
4585            convert_to_string(&name_node.u.constant);
4586        }
4587    }
4588
4589    if (zend_try_compile_cv(&result, var_ast TSRMLS_CC) == SUCCESS) {
4590        zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
4591    } else {
4592        zend_emit_op(&result, ZEND_FETCH_W, &name_node, NULL TSRMLS_CC);
4593
4594        // TODO.AST Avoid double fetch
4595        //opline->extended_value = ZEND_FETCH_GLOBAL_LOCK;
4596
4597        zend_emit_assign_ref_znode(var_ast, &result TSRMLS_CC);
4598    }
4599}
4600/* }}} */
4601
4602static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_bool by_ref TSRMLS_DC) /* {{{ */
4603{
4604    znode var_node, result;
4605    zend_op *opline;
4606
4607    zend_compile_expr(&var_node, var_ast TSRMLS_CC);
4608
4609    if (!CG(active_op_array)->static_variables) {
4610        if (CG(active_op_array)->scope) {
4611            CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
4612        }
4613        ALLOC_HASHTABLE(CG(active_op_array)->static_variables);
4614        zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0);
4615    }
4616
4617    zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
4618
4619    opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL TSRMLS_CC);
4620    opline->extended_value = ZEND_FETCH_STATIC;
4621
4622    if (by_ref) {
4623        zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast);
4624        zend_emit_assign_ref_znode(fetch_ast, &result TSRMLS_CC);
4625    } else {
4626        zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast);
4627        zend_emit_assign_znode(fetch_ast, &result TSRMLS_CC);
4628    }
4629}
4630/* }}} */
4631
4632void zend_compile_static_var(zend_ast *ast TSRMLS_DC) /* {{{ */
4633{
4634    zend_ast *var_ast = ast->child[0];
4635    zend_ast *value_ast = ast->child[1];
4636    zval value_zv;
4637
4638    if (value_ast) {
4639        zend_const_expr_to_zval(&value_zv, value_ast TSRMLS_CC);
4640    } else {
4641        ZVAL_NULL(&value_zv);
4642    }
4643
4644    zend_compile_static_var_common(var_ast, &value_zv, 1 TSRMLS_CC);
4645}
4646/* }}} */
4647
4648void zend_compile_unset(zend_ast *ast TSRMLS_DC) /* {{{ */
4649{
4650    zend_ast *var_ast = ast->child[0];
4651
4652    znode var_node;
4653    zend_op *opline;
4654    switch (var_ast->kind) {
4655        case ZEND_AST_VAR:
4656            if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) {
4657                opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL TSRMLS_CC);
4658                opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
4659            } else {
4660                opline = zend_compile_simple_var_no_cv(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
4661                opline->opcode = ZEND_UNSET_VAR;
4662            }
4663            return;
4664        case ZEND_AST_DIM:
4665            opline = zend_compile_dim_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
4666            opline->opcode = ZEND_UNSET_DIM;
4667            return;
4668        case ZEND_AST_PROP:
4669            opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
4670            opline->opcode = ZEND_UNSET_OBJ;
4671            return;
4672        case ZEND_AST_STATIC_PROP:
4673            opline = zend_compile_static_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
4674            opline->opcode = ZEND_UNSET_VAR;
4675            return;
4676        EMPTY_SWITCH_DEFAULT_CASE()
4677    }
4678}
4679/* }}} */
4680
4681static void zend_free_foreach_and_switch_variables(TSRMLS_D) /* {{{ */
4682{
4683    uint32_t opnum_start, opnum_end, i;
4684
4685    opnum_start = get_next_op_number(CG(active_op_array));
4686
4687#ifdef ZTS
4688    zend_stack_apply_with_argument(&CG(loop_var_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_loop_var TSRMLS_CC);
4689#else
4690    zend_stack_apply(&CG(loop_var_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_loop_var);
4691#endif
4692
4693    opnum_end = get_next_op_number(CG(active_op_array));
4694
4695    for (i = opnum_start; i < opnum_end; ++i) {
4696        CG(active_op_array)->opcodes[i].extended_value |= EXT_TYPE_FREE_ON_RETURN;
4697    }
4698}
4699/* }}} */
4700
4701void zend_compile_return(zend_ast *ast TSRMLS_DC) /* {{{ */
4702{
4703    zend_ast *expr_ast = ast->child[0];
4704    zend_bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
4705
4706    znode expr_node;
4707    zend_op *opline;
4708
4709    if (!expr_ast) {
4710        expr_node.op_type = IS_CONST;
4711        ZVAL_NULL(&expr_node.u.constant);
4712    } else if (by_ref && zend_is_variable(expr_ast) && !zend_is_call(expr_ast)) {
4713        zend_compile_var(&expr_node, expr_ast, BP_VAR_REF TSRMLS_CC);
4714    } else {
4715        zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
4716    }
4717
4718    zend_free_foreach_and_switch_variables(TSRMLS_C);
4719
4720    if (CG(context).in_finally) {
4721        zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL TSRMLS_CC);
4722    }
4723
4724    opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
4725        &expr_node, NULL TSRMLS_CC);
4726
4727    if (expr_ast) {
4728        if (zend_is_call(expr_ast)) {
4729            opline->extended_value = ZEND_RETURNS_FUNCTION;
4730        } else if (!zend_is_variable(expr_ast)) {
4731            opline->extended_value = ZEND_RETURNS_VALUE;
4732        }
4733    }
4734}
4735/* }}} */
4736
4737void zend_compile_echo(zend_ast *ast TSRMLS_DC) /* {{{ */
4738{
4739    zend_ast *expr_ast = ast->child[0];
4740
4741    znode expr_node;
4742    zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
4743
4744    zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL TSRMLS_CC);
4745}
4746/* }}} */
4747
4748void zend_compile_throw(zend_ast *ast TSRMLS_DC) /* {{{ */
4749{
4750    zend_ast *expr_ast = ast->child[0];
4751
4752    znode expr_node;
4753    zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
4754
4755    zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL TSRMLS_CC);
4756}
4757/* }}} */
4758
4759void zend_compile_break_continue(zend_ast *ast TSRMLS_DC) /* {{{ */
4760{
4761    zend_ast *depth_ast = ast->child[0];
4762
4763    znode depth_node;
4764    zend_op *opline;
4765
4766    ZEND_ASSERT(ast->kind == ZEND_AST_BREAK || ast->kind == ZEND_AST_CONTINUE);
4767
4768    if (depth_ast) {
4769        if (depth_ast->kind != ZEND_AST_ZVAL) {
4770            zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-constant operand "
4771                "is no longer supported", ast->kind == ZEND_AST_BREAK ? "break" : "continue");
4772        }
4773
4774        zend_compile_expr(&depth_node, depth_ast TSRMLS_CC);
4775
4776        if (Z_TYPE(depth_node.u.constant) != IS_LONG || Z_LVAL(depth_node.u.constant) < 1) {
4777            zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive numbers",
4778                ast->kind == ZEND_AST_BREAK ? "break" : "continue");
4779        }
4780    } else {
4781        depth_node.op_type = IS_CONST;
4782        ZVAL_LONG(&depth_node.u.constant, 1);
4783    }
4784
4785    opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT,
4786        NULL, &depth_node TSRMLS_CC);
4787    opline->op1.opline_num = CG(context).current_brk_cont;
4788}
4789/* }}} */
4790
4791void zend_compile_goto(zend_ast *ast TSRMLS_DC) /* {{{ */
4792{
4793    zend_ast *label_ast = ast->child[0];
4794    znode label_node;
4795    zend_op *opline;
4796
4797    zend_compile_expr(&label_node, label_ast TSRMLS_CC);
4798    opline = zend_emit_op(NULL, ZEND_GOTO, NULL, &label_node TSRMLS_CC);
4799    opline->extended_value = CG(context).current_brk_cont;
4800    zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC);
4801}
4802/* }}} */
4803
4804void zend_compile_label(zend_ast *ast TSRMLS_DC) /* {{{ */
4805{
4806    zval *label = zend_ast_get_zval(ast->child[0]);
4807    zend_label dest;
4808
4809    ZEND_ASSERT(Z_TYPE_P(label) == IS_STRING);
4810
4811    if (!CG(context).labels) {
4812        ALLOC_HASHTABLE(CG(context).labels);
4813        zend_hash_init(CG(context).labels, 8, NULL, ptr_dtor, 0);
4814    }
4815
4816    dest.brk_cont = CG(context).current_brk_cont;
4817    dest.opline_num = get_next_op_number(CG(active_op_array));
4818
4819    if (!zend_hash_add_mem(CG(context).labels, Z_STR_P(label), &dest, sizeof(zend_label))) {
4820        zend_error_noreturn(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL_P(label));
4821    }
4822}
4823/* }}} */
4824
4825void zend_compile_while(zend_ast *ast TSRMLS_DC) /* {{{ */
4826{
4827    zend_ast *cond_ast = ast->child[0];
4828    zend_ast *stmt_ast = ast->child[1];
4829
4830    znode cond_node;
4831    uint32_t opnum_start, opnum_jmpz;
4832
4833    opnum_start = get_next_op_number(CG(active_op_array));
4834    zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
4835
4836    opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0 TSRMLS_CC);
4837    zend_begin_loop(TSRMLS_C);
4838
4839    zend_compile_stmt(stmt_ast TSRMLS_CC);
4840
4841    zend_emit_jump(opnum_start TSRMLS_CC);
4842
4843    zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC);
4844
4845    zend_end_loop(opnum_start, 0 TSRMLS_CC);
4846}
4847/* }}} */
4848
4849void zend_compile_do_while(zend_ast *ast TSRMLS_DC) /* {{{ */
4850{
4851    zend_ast *stmt_ast = ast->child[0];
4852    zend_ast *cond_ast = ast->child[1];
4853
4854    znode cond_node;
4855    uint32_t opnum_start, opnum_cond;
4856
4857    zend_begin_loop(TSRMLS_C);
4858
4859    opnum_start = get_next_op_number(CG(active_op_array));
4860    zend_compile_stmt(stmt_ast TSRMLS_CC);
4861
4862    opnum_cond = get_next_op_number(CG(active_op_array));
4863    zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
4864
4865    zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start TSRMLS_CC);
4866
4867    zend_end_loop(opnum_cond, 0 TSRMLS_CC);
4868}
4869/* }}} */
4870
4871void zend_compile_expr_list(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
4872{
4873    zend_ast_list *list;
4874    uint32_t i;
4875
4876    result->op_type = IS_CONST;
4877    ZVAL_TRUE(&result->u.constant);
4878
4879    if (!ast) {
4880        return;
4881    }
4882
4883    list = zend_ast_get_list(ast);
4884    for (i = 0; i < list->children; ++i) {
4885        zend_ast *expr_ast = list->child[i];
4886
4887        zend_do_free(result TSRMLS_CC);
4888        zend_compile_expr(result, expr_ast TSRMLS_CC);
4889    }
4890}
4891/* }}} */
4892
4893void zend_compile_for(zend_ast *ast TSRMLS_DC) /* {{{ */
4894{
4895    zend_ast *init_ast = ast->child[0];
4896    zend_ast *cond_ast = ast->child[1];
4897    zend_ast *loop_ast = ast->child[2];
4898    zend_ast *stmt_ast = ast->child[3];
4899
4900    znode result;
4901    uint32_t opnum_cond, opnum_jmpz, opnum_loop;
4902
4903    zend_compile_expr_list(&result, init_ast TSRMLS_CC);
4904    zend_do_free(&result TSRMLS_CC);
4905
4906    opnum_cond = get_next_op_number(CG(active_op_array));
4907    zend_compile_expr_list(&result, cond_ast TSRMLS_CC);
4908    zend_do_extended_info(TSRMLS_C);
4909
4910    opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &result, 0 TSRMLS_CC);
4911    zend_begin_loop(TSRMLS_C);
4912
4913    zend_compile_stmt(stmt_ast TSRMLS_CC);
4914
4915    opnum_loop = get_next_op_number(CG(active_op_array));
4916    zend_compile_expr_list(&result, loop_ast TSRMLS_CC);
4917    zend_do_free(&result TSRMLS_CC);
4918
4919    zend_emit_jump(opnum_cond TSRMLS_CC);
4920
4921    zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC);
4922
4923    zend_end_loop(opnum_loop, 0 TSRMLS_CC);
4924}
4925/* }}} */
4926
4927void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */
4928{
4929    zend_ast *expr_ast = ast->child[0];
4930    zend_ast *value_ast = ast->child[1];
4931    zend_ast *key_ast = ast->child[2];
4932    zend_ast *stmt_ast = ast->child[3];
4933    zend_bool by_ref = value_ast->kind == ZEND_AST_REF;
4934    zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast)
4935        && zend_can_write_to_variable(expr_ast);
4936
4937    znode expr_node, reset_node, value_node, key_node, dummy_node;
4938    zend_op *opline;
4939    uint32_t opnum_reset, opnum_fetch;
4940
4941    if (key_ast) {
4942        if (key_ast->kind == ZEND_AST_REF) {
4943            zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference");
4944        }
4945        if (key_ast->kind == ZEND_AST_LIST) {
4946            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element");
4947        }
4948    }
4949
4950    if (by_ref) {
4951        value_ast = value_ast->child[0];
4952    }
4953
4954    if (by_ref && is_variable) {
4955        zend_compile_var(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC);
4956    } else {
4957        zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
4958    }
4959
4960    opnum_reset = get_next_op_number(CG(active_op_array));
4961    opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL TSRMLS_CC);
4962    if (by_ref && is_variable) {
4963        opline->extended_value = ZEND_FE_RESET_VARIABLE | ZEND_FE_RESET_REFERENCE; // ???
4964    }
4965
4966    zend_stack_push(&CG(loop_var_stack), &reset_node);
4967
4968    opnum_fetch = get_next_op_number(CG(active_op_array));
4969    opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL TSRMLS_CC);
4970    if (by_ref) {
4971        opline->extended_value |= ZEND_FE_FETCH_BYREF;
4972    }
4973    if (key_ast) {
4974        opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
4975    }
4976
4977    opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL TSRMLS_CC);
4978
4979    /* Allocate enough space to keep HashPointer on VM stack */
4980    opline->op1_type = IS_TMP_VAR;
4981    opline->op1.var = get_temporary_variable(CG(active_op_array));
4982    if (sizeof(HashPointer) > sizeof(zval)) {
4983        /* Make sure 1 zval is enough for HashPointer (2 must be enough) */
4984        get_temporary_variable(CG(active_op_array));
4985    }
4986
4987    if (key_ast) {
4988        zend_make_tmp_result(&key_node, opline TSRMLS_CC);
4989    }
4990
4991    if (value_ast->attr == ZEND_AST_LIST) {
4992        zend_compile_list_assign(&dummy_node, value_ast, &value_node TSRMLS_CC);
4993        zend_do_free(&dummy_node TSRMLS_CC);
4994    } else if (by_ref) {
4995        zend_emit_assign_ref_znode(value_ast, &value_node TSRMLS_CC);
4996    } else {
4997        zend_emit_assign_znode(value_ast, &value_node TSRMLS_CC);
4998    }
4999
5000    if (key_ast) {
5001        zend_emit_assign_znode(key_ast, &key_node TSRMLS_CC);
5002    }
5003
5004    zend_begin_loop(TSRMLS_C);
5005
5006    zend_compile_stmt(stmt_ast TSRMLS_CC);
5007
5008    zend_emit_jump(opnum_fetch TSRMLS_CC);
5009
5010    opline = &CG(active_op_array)->opcodes[opnum_reset];
5011    opline->op2.opline_num = get_next_op_number(CG(active_op_array));
5012
5013    opline = &CG(active_op_array)->opcodes[opnum_fetch];
5014    opline->op2.opline_num = get_next_op_number(CG(active_op_array));
5015
5016    zend_end_loop(opnum_fetch, 1 TSRMLS_CC);
5017
5018    generate_free_loop_var(&reset_node TSRMLS_CC);
5019    zend_stack_del_top(&CG(loop_var_stack));
5020}
5021/* }}} */
5022
5023void zend_compile_if(zend_ast *ast TSRMLS_DC) /* {{{ */
5024{
5025    zend_ast_list *list = zend_ast_get_list(ast);
5026    uint32_t i;
5027    uint32_t *jmp_opnums;
5028
5029    if (list->children > 1) {
5030        jmp_opnums = safe_emalloc(sizeof(uint32_t), list->children - 1, 0);
5031    }
5032
5033    for (i = 0; i < list->children; ++i) {
5034        zend_ast *elem_ast = list->child[i];
5035        zend_ast *cond_ast = elem_ast->child[0];
5036        zend_ast *stmt_ast = elem_ast->child[1];
5037
5038        znode cond_node;
5039        uint32_t opnum_jmpz;
5040        if (cond_ast) {
5041            zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
5042            opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0 TSRMLS_CC);
5043        }
5044
5045        zend_compile_stmt(stmt_ast TSRMLS_CC);
5046
5047        if (i != list->children - 1) {
5048            jmp_opnums[i] = zend_emit_jump(0 TSRMLS_CC);
5049        }
5050
5051        if (cond_ast) {
5052            zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC);
5053        }
5054    }
5055
5056    if (list->children > 1) {
5057        for (i = 0; i < list->children - 1; ++i) {
5058            zend_update_jump_target_to_next(jmp_opnums[i] TSRMLS_CC);
5059        }
5060        efree(jmp_opnums);
5061    }
5062}
5063/* }}} */
5064
5065void zend_compile_switch(zend_ast *ast TSRMLS_DC) /* {{{ */
5066{
5067    zend_ast *expr_ast = ast->child[0];
5068    zend_ast_list *cases = zend_ast_get_list(ast->child[1]);
5069
5070    uint32_t i;
5071    zend_bool has_default_case = 0;
5072
5073    znode expr_node, case_node;
5074    zend_op *opline;
5075    uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
5076    uint32_t opnum_default_jmp;
5077
5078    zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
5079
5080    zend_stack_push(&CG(loop_var_stack), &expr_node);
5081
5082    zend_begin_loop(TSRMLS_C);
5083
5084    case_node.op_type = IS_TMP_VAR;
5085    case_node.u.op.var = get_temporary_variable(CG(active_op_array));
5086
5087    for (i = 0; i < cases->children; ++i) {
5088        zend_ast *case_ast = cases->child[i];
5089        zend_ast *cond_ast = case_ast->child[0];
5090        znode cond_node;
5091
5092        if (!cond_ast) {
5093            has_default_case = 1;
5094            continue;
5095        }
5096
5097        zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
5098
5099        opline = zend_emit_op(NULL, ZEND_CASE, &expr_node, &cond_node TSRMLS_CC);
5100        SET_NODE(opline->result, &case_node);
5101        if (opline->op1_type == IS_CONST) {
5102            zval_copy_ctor(&CONSTANT(opline->op1.constant));
5103        }
5104
5105        jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0 TSRMLS_CC);
5106    }
5107
5108    opnum_default_jmp = zend_emit_jump(0 TSRMLS_CC);
5109
5110    for (i = 0; i < cases->children; ++i) {
5111        zend_ast *case_ast = cases->child[i];
5112        zend_ast *cond_ast = case_ast->child[0];
5113        zend_ast *stmt_ast = case_ast->child[1];
5114
5115        if (cond_ast) {
5116            zend_update_jump_target_to_next(jmpnz_opnums[i] TSRMLS_CC);
5117        } else {
5118            zend_update_jump_target_to_next(opnum_default_jmp TSRMLS_CC);
5119        }
5120
5121        zend_compile_stmt(stmt_ast TSRMLS_CC);
5122    }
5123
5124    if (!