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) {
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_ptr_dtor_nogc(&op1->u.constant);
604    }
605}
606/* }}} */
607
608uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
609{
610    uint32_t new_flags = flags | new_flag;
611    if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
612        zend_error_noreturn(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
613    }
614    if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
615        zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
616    }
617    if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
618        zend_error_noreturn(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
619    }
620    if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
621        zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
622    }
623    if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
624        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
625    }
626    return new_flags;
627}
628/* }}} */
629
630zend_string *zend_concat3(char *str1, size_t str1_len, char *str2, size_t str2_len, char *str3, size_t str3_len) /* {{{ */
631{
632    size_t len = str1_len + str2_len + str3_len;
633    zend_string *res = zend_string_alloc(len, 0);
634
635    memcpy(res->val, str1, str1_len);
636    memcpy(res->val + str1_len, str2, str2_len);
637    memcpy(res->val + str1_len + str2_len, str3, str3_len);
638    res->val[len] = '\0';
639
640    return res;
641}
642
643zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2, size_t name2_len) {
644    return zend_concat3(name1, name1_len, "\\", 1, name2, name2_len);
645}
646
647zend_string *zend_prefix_with_ns(zend_string *name TSRMLS_DC) {
648    if (CG(current_namespace)) {
649        zend_string *ns = CG(current_namespace);
650        return zend_concat_names(ns->val, ns->len, name->val, name->len);
651    } else {
652        return zend_string_copy(name);
653    }
654}
655
656void *zend_hash_find_ptr_lc(HashTable *ht, char *str, size_t len) {
657    void *result;
658    zend_string *lcname = zend_string_alloc(len, 0);
659    zend_str_tolower_copy(lcname->val, str, len);
660    result = zend_hash_find_ptr(ht, lcname);
661    zend_string_free(lcname);
662    return result;
663}
664
665zend_string *zend_resolve_non_class_name(
666    zend_string *name, uint32_t type, zend_bool *is_fully_qualified,
667    zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC
668) {
669    char *compound;
670    *is_fully_qualified = 0;
671
672    if (name->val[0] == '\\') {
673        /* Remove \ prefix (only relevant if this is a string rather than a label) */
674        return zend_string_init(name->val + 1, name->len - 1, 0);
675    }
676
677    if (type == ZEND_NAME_FQ) {
678        *is_fully_qualified = 1;
679        return zend_string_copy(name);
680    }
681
682    if (type == ZEND_NAME_RELATIVE) {
683        *is_fully_qualified = 1;
684        return zend_prefix_with_ns(name TSRMLS_CC);
685    }
686
687    if (current_import_sub) {
688        /* If an unqualified name is a function/const alias, replace it. */
689        zend_string *import_name;
690        if (case_sensitive) {
691            import_name = zend_hash_find_ptr(current_import_sub, name);
692        } else {
693            import_name = zend_hash_find_ptr_lc(current_import_sub, name->val, name->len);
694        }
695
696        if (import_name) {
697            *is_fully_qualified = 1;
698            return zend_string_copy(import_name);
699        }
700    }
701
702    compound = memchr(name->val, '\\', name->len);
703    if (compound) {
704        *is_fully_qualified = 1;
705    }
706
707    if (compound && CG(current_import)) {
708        /* If the first part of a qualified name is an alias, substitute it. */
709        size_t len = compound - name->val;
710        zend_string *import_name = zend_hash_find_ptr_lc(CG(current_import), name->val, len);
711
712        if (import_name) {
713            return zend_concat_names(
714                import_name->val, import_name->len, name->val + len + 1, name->len - len - 1);
715        }
716    }
717
718    return zend_prefix_with_ns(name TSRMLS_CC);
719}
720/* }}} */
721
722zend_string *zend_resolve_function_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified TSRMLS_DC) /* {{{ */
723{
724    return zend_resolve_non_class_name(
725        name, type, is_fully_qualified, 0, CG(current_import_function) TSRMLS_CC);
726}
727/* }}} */
728
729zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified TSRMLS_DC) /* {{{ */ {
730    return zend_resolve_non_class_name(
731        name, type, is_fully_qualified, 1, CG(current_import_const) TSRMLS_CC);
732}
733/* }}} */
734
735zend_string *zend_resolve_class_name(zend_string *name, uint32_t type TSRMLS_DC) /* {{{ */
736{
737    char *compound;
738
739    if (type == ZEND_NAME_RELATIVE) {
740        return zend_prefix_with_ns(name TSRMLS_CC);
741    }
742
743    if (type == ZEND_NAME_FQ || name->val[0] == '\\') {
744        /* Remove \ prefix (only relevant if this is a string rather than a label) */
745        if (name->val[0] == '\\') {
746            name = zend_string_init(name->val + 1, name->len - 1, 0);
747        } else {
748            zend_string_addref(name);
749        }
750        /* Ensure that \self, \parent and \static are not used */
751        if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
752            zend_error_noreturn(E_COMPILE_ERROR, "'\\%s' is an invalid class name", name->val);
753        }
754        return name;
755    }
756
757    if (CG(current_import)) {
758        compound = memchr(name->val, '\\', name->len);
759        if (compound) {
760            /* If the first part of a qualified name is an alias, substitute it. */
761            size_t len = compound - name->val;
762            zend_string *import_name = zend_hash_find_ptr_lc(CG(current_import), name->val, len);
763
764            if (import_name) {
765                return zend_concat_names(
766                    import_name->val, import_name->len, name->val + len + 1, name->len - len - 1);
767            }
768        } else {
769            /* If an unqualified name is an alias, replace it. */
770            zend_string *import_name
771                = zend_hash_find_ptr_lc(CG(current_import), name->val, name->len);
772
773            if (import_name) {
774                return zend_string_copy(import_name);
775            }
776        }
777    }
778
779    /* If not fully qualified and not an alias, prepend the current namespace */
780    return zend_prefix_with_ns(name TSRMLS_CC);
781}
782/* }}} */
783
784zend_string *zend_resolve_class_name_ast(zend_ast *ast TSRMLS_DC) /* {{{ */
785{
786    zend_string *name = zend_ast_get_str(ast);
787    return zend_resolve_class_name(name, ast->attr TSRMLS_CC);
788}
789/* }}} */
790
791static void ptr_dtor(zval *zv) /* {{{ */
792{
793    efree(Z_PTR_P(zv));
794}
795/* }}} */
796
797static void str_dtor(zval *zv)  /* {{{ */ {
798    zend_string_release(Z_STR_P(zv));
799}
800/* }}} */
801
802void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */
803{
804    zend_label *dest;
805    zend_long current, distance;
806    zval *label;
807
808    if (pass2) {
809        label = opline->op2.zv;
810    } else {
811        label = &CONSTANT_EX(op_array, opline->op2.constant);
812    }
813    if (CG(context).labels == NULL ||
814        (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) {
815
816        if (pass2) {
817            CG(in_compilation) = 1;
818            CG(active_op_array) = op_array;
819            CG(zend_lineno) = opline->lineno;
820            zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
821        } else {
822            /* Label is not defined. Delay to pass 2. */
823            return;
824        }
825    }
826
827    opline->op1.opline_num = dest->opline_num;
828    zval_dtor(label);
829    ZVAL_NULL(label);
830
831    /* Check that we are not moving into loop or switch */
832    current = opline->extended_value;
833    for (distance = 0; current != dest->brk_cont; distance++) {
834        if (current == -1) {
835            if (pass2) {
836                CG(in_compilation) = 1;
837                CG(active_op_array) = op_array;
838                CG(zend_lineno) = opline->lineno;
839            }
840            zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
841        }
842        current = op_array->brk_cont_array[current].parent;
843    }
844
845    if (distance == 0) {
846        /* Nothing to break out of, optimize to ZEND_JMP */
847        opline->opcode = ZEND_JMP;
848        opline->extended_value = 0;
849        SET_UNUSED(opline->op2);
850    } else {
851        /* Set real break distance */
852        ZVAL_LONG(label, distance);
853    }
854}
855/* }}} */
856
857void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
858{
859    if (CG(context).labels) {
860        zend_hash_destroy(CG(context).labels);
861        FREE_HASHTABLE(CG(context).labels);
862        CG(context).labels = NULL;
863    }
864    if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
865        zend_compiler_context *ctx = zend_stack_top(&CG(context_stack));
866        CG(context) = *ctx;
867        zend_stack_del_top(&CG(context_stack));
868    }
869}
870/* }}} */
871
872static zend_bool zend_is_call(zend_ast *ast);
873
874static int generate_free_loop_var(znode *var TSRMLS_DC) /* {{{ */
875{
876    switch (var->op_type) {
877        case IS_UNUSED:
878            /* Stack separator on function boundary, stop applying */
879            return 1;
880        case IS_VAR:
881        case IS_TMP_VAR:
882        {
883            zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
884
885            opline->opcode = var->op_type == IS_TMP_VAR ? ZEND_FREE : ZEND_SWITCH_FREE;
886            SET_NODE(opline->op1, var);
887            SET_UNUSED(opline->op2);
888        }
889    }
890
891    return 0;
892}
893/* }}} */
894
895static uint32_t zend_add_try_element(uint32_t try_op TSRMLS_DC) /* {{{ */
896{
897    zend_op_array *op_array = CG(active_op_array);
898    uint32_t try_catch_offset = op_array->last_try_catch++;
899    zend_try_catch_element *elem;
900
901    op_array->try_catch_array = safe_erealloc(
902        op_array->try_catch_array, sizeof(zend_try_catch_element), op_array->last_try_catch, 0);
903
904    elem = &op_array->try_catch_array[try_catch_offset];
905    elem->try_op = try_op;
906    elem->catch_op = 0;
907    elem->finally_op = 0;
908    elem->finally_end = 0;
909
910    return try_catch_offset;
911}
912/* }}} */
913
914ZEND_API void function_add_ref(zend_function *function) /* {{{ */
915{
916    if (function->type == ZEND_USER_FUNCTION) {
917        zend_op_array *op_array = &function->op_array;
918
919        (*op_array->refcount)++;
920        if (op_array->static_variables) {
921            HashTable *static_variables = op_array->static_variables;
922
923            ALLOC_HASHTABLE(op_array->static_variables);
924            zend_array_dup(op_array->static_variables, static_variables);
925        }
926        op_array->run_time_cache = NULL;
927    } else if (function->type == ZEND_INTERNAL_FUNCTION) {
928        if (function->common.function_name) {
929            zend_string_addref(function->common.function_name);
930        }
931    }
932}
933/* }}} */
934
935static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) /* {{{ */
936{
937    zend_function *function, *new_function;
938
939    if (!ce->parent) {
940        return;
941    }
942
943    /* You cannot change create_object */
944    ce->create_object = ce->parent->create_object;
945
946    /* Inherit special functions if needed */
947    if (!ce->get_iterator) {
948        ce->get_iterator = ce->parent->get_iterator;
949    }
950    if (!ce->iterator_funcs.funcs) {
951        ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
952    }
953    if (!ce->__get) {
954        ce->__get   = ce->parent->__get;
955    }
956    if (!ce->__set) {
957        ce->__set = ce->parent->__set;
958    }
959    if (!ce->__unset) {
960        ce->__unset = ce->parent->__unset;
961    }
962    if (!ce->__isset) {
963        ce->__isset = ce->parent->__isset;
964    }
965    if (!ce->__call) {
966        ce->__call = ce->parent->__call;
967    }
968    if (!ce->__callstatic) {
969        ce->__callstatic = ce->parent->__callstatic;
970    }
971    if (!ce->__tostring) {
972        ce->__tostring = ce->parent->__tostring;
973    }
974    if (!ce->clone) {
975        ce->clone = ce->parent->clone;
976    }
977    if(!ce->serialize) {
978        ce->serialize = ce->parent->serialize;
979    }
980    if(!ce->unserialize) {
981        ce->unserialize = ce->parent->unserialize;
982    }
983    if (!ce->destructor) {
984        ce->destructor   = ce->parent->destructor;
985    }
986    if (!ce->__debugInfo) {
987        ce->__debugInfo = ce->parent->__debugInfo;
988    }
989    if (ce->constructor) {
990        if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
991            zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
992                ce->parent->name->val, ce->parent->constructor->common.function_name->val,
993                ce->name->val, ce->constructor->common.function_name->val
994                );
995        }
996        return;
997    }
998
999    if ((function = zend_hash_str_find_ptr(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) != NULL) {
1000        /* inherit parent's constructor */
1001        if (function->type == ZEND_INTERNAL_FUNCTION) {
1002            new_function = pemalloc(sizeof(zend_internal_function), 1);
1003            memcpy(new_function, function, sizeof(zend_internal_function));
1004        } else {
1005            new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1006            memcpy(new_function, function, sizeof(zend_op_array));
1007        }
1008        zend_hash_str_update_ptr(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1, new_function);
1009        function_add_ref(new_function);
1010    } else {
1011        /* Don't inherit the old style constructor if we already have the new style constructor */
1012        zend_string *lc_class_name;
1013        zend_string *lc_parent_class_name;
1014
1015        lc_class_name = zend_string_alloc(ce->name->len, 0);
1016        zend_str_tolower_copy(lc_class_name->val, ce->name->val, ce->name->len);
1017        if (!zend_hash_exists(&ce->function_table, lc_class_name)) {
1018            lc_parent_class_name = zend_string_alloc(ce->parent->name->len, 0);
1019            zend_str_tolower_copy(lc_parent_class_name->val, ce->parent->name->val, ce->parent->name->len);
1020            if (!zend_hash_exists(&ce->function_table, lc_parent_class_name) &&
1021                    (function = zend_hash_find_ptr(&ce->parent->function_table, lc_parent_class_name)) != NULL) {
1022                if (function->common.fn_flags & ZEND_ACC_CTOR) {
1023                    /* inherit parent's constructor */
1024                    new_function = pemalloc(sizeof(zend_function), function->type == ZEND_INTERNAL_FUNCTION);
1025                    memcpy(new_function, function, sizeof(zend_function));
1026                    zend_hash_update_ptr(&ce->function_table, lc_parent_class_name, new_function);
1027                    function_add_ref(new_function);
1028                }
1029            }
1030            zend_string_release(lc_parent_class_name);
1031        }
1032        zend_string_free(lc_class_name);
1033    }
1034    ce->constructor = ce->parent->constructor;
1035}
1036/* }}} */
1037
1038char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
1039{
1040    if (fn_flags & ZEND_ACC_PRIVATE) {
1041        return "private";
1042    }
1043    if (fn_flags & ZEND_ACC_PROTECTED) {
1044        return "protected";
1045    }
1046    if (fn_flags & ZEND_ACC_PUBLIC) {
1047        return "public";
1048    }
1049    return "";
1050}
1051/* }}} */
1052
1053static zend_function *do_inherit_method(zend_function *old_function TSRMLS_DC) /* {{{ */
1054{
1055    zend_function *new_function;
1056
1057    if (old_function->type == ZEND_INTERNAL_FUNCTION) {
1058        new_function = pemalloc(sizeof(zend_internal_function), 1);
1059        memcpy(new_function, old_function, sizeof(zend_internal_function));
1060    } else {
1061        new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1062        memcpy(new_function, old_function, sizeof(zend_op_array));
1063    }
1064    /* The class entry of the derived function intentionally remains the same
1065     * as that of the parent class.  That allows us to know in which context
1066     * we're running, and handle private method calls properly.
1067     */
1068    function_add_ref(new_function);
1069    return new_function;
1070}
1071/* }}} */
1072
1073static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
1074{
1075    uint32_t i, num_args;
1076
1077    /* If it's a user function then arg_info == NULL means we don't have any parameters but
1078     * we still need to do the arg number checks.  We are only willing to ignore this for internal
1079     * functions because extensions don't always define arg_info.
1080     */
1081    if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
1082        return 1;
1083    }
1084
1085    /* Checks for constructors only if they are declared in an interface,
1086     * or explicitly marked as abstract
1087     */
1088    if ((fe->common.fn_flags & ZEND_ACC_CTOR)
1089        && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
1090            && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
1091        return 1;
1092    }
1093
1094    /* If both methods are private do not enforce a signature */
1095    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
1096        return 1;
1097    }
1098
1099    /* check number of arguments */
1100    if (proto->common.required_num_args < fe->common.required_num_args
1101        || proto->common.num_args > fe->common.num_args) {
1102        return 0;
1103    }
1104
1105    /* by-ref constraints on return values are covariant */
1106    if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1107        && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
1108        return 0;
1109    }
1110
1111    if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
1112        && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
1113        return 0;
1114    }
1115
1116    /* For variadic functions any additional (optional) arguments that were added must be
1117     * checked against the signature of the variadic argument, so in this case we have to
1118     * go through all the parameters of the function and not just those present in the
1119     * prototype. */
1120    num_args = proto->common.num_args;
1121    if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
1122        && fe->common.num_args > proto->common.num_args) {
1123        num_args = fe->common.num_args;
1124    }
1125
1126    for (i = 0; i < num_args; i++) {
1127        zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
1128
1129        zend_arg_info *proto_arg_info;
1130        if (i < proto->common.num_args) {
1131            proto_arg_info = &proto->common.arg_info[i];
1132        } else {
1133            proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
1134        }
1135
1136        if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
1137            /* Only one has a type hint and the other one doesn't */
1138            return 0;
1139        }
1140
1141        if (fe_arg_info->class_name) {
1142            zend_string *fe_class_name, *proto_class_name;
1143
1144            if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
1145                fe_class_name = zend_string_copy(proto->common.scope->name);
1146            } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
1147                fe_class_name = zend_string_copy(fe->common.scope->name);
1148            } else {
1149                fe_class_name = zend_string_init(
1150                    fe_arg_info->class_name,
1151                    fe_arg_info->class_name_len, 0);
1152            }
1153
1154            if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
1155                proto_class_name = zend_string_copy(proto->common.scope->parent->name);
1156            } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
1157                proto_class_name = zend_string_copy(proto->common.scope->name);
1158            } else {
1159                proto_class_name = zend_string_init(
1160                    proto_arg_info->class_name,
1161                    proto_arg_info->class_name_len, 0);
1162            }
1163
1164            if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
1165                const char *colon;
1166
1167                if (fe->common.type != ZEND_USER_FUNCTION) {
1168                    zend_string_release(proto_class_name);
1169                    zend_string_release(fe_class_name);
1170                    return 0;
1171                } else if (strchr(proto_class_name->val, '\\') != NULL ||
1172                        (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL ||
1173                        strcasecmp(colon+1, proto_class_name->val) != 0) {
1174                    zend_class_entry *fe_ce, *proto_ce;
1175
1176                    fe_ce = zend_lookup_class(fe_class_name TSRMLS_CC);
1177                    proto_ce = zend_lookup_class(proto_class_name TSRMLS_CC);
1178
1179                    /* Check for class alias */
1180                    if (!fe_ce || !proto_ce ||
1181                            fe_ce->type == ZEND_INTERNAL_CLASS ||
1182                            proto_ce->type == ZEND_INTERNAL_CLASS ||
1183                            fe_ce != proto_ce) {
1184                        zend_string_release(proto_class_name);
1185                        zend_string_release(fe_class_name);
1186                        return 0;
1187                    }
1188                }
1189            }
1190            zend_string_release(proto_class_name);
1191            zend_string_release(fe_class_name);
1192        }
1193        if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
1194            /* Incompatible type hint */
1195            return 0;
1196        }
1197
1198        /* by-ref constraints on arguments are invariant */
1199        if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
1200            return 0;
1201        }
1202    }
1203
1204    return 1;
1205}
1206/* }}} */
1207
1208#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
1209    if (UNEXPECTED(offset - buf + size >= length)) {    \
1210        length += size + 1;                 \
1211        buf = erealloc(buf, length);        \
1212    }
1213
1214static char *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
1215{
1216    char *offset, *buf;
1217    uint32_t length = 1024;
1218
1219    offset = buf = (char *)emalloc(length * sizeof(char));
1220    if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
1221        *(offset++) = '&';
1222        *(offset++) = ' ';
1223    }
1224
1225    if (fptr->common.scope) {
1226        memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len);
1227        offset += fptr->common.scope->name->len;
1228        *(offset++) = ':';
1229        *(offset++) = ':';
1230    }
1231
1232    {
1233        size_t name_len = fptr->common.function_name->len;
1234        REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
1235        memcpy(offset, fptr->common.function_name->val, name_len);
1236        offset += name_len;
1237    }
1238
1239    *(offset++) = '(';
1240    if (fptr->common.arg_info) {
1241        uint32_t i, required;
1242        zend_arg_info *arg_info = fptr->common.arg_info;
1243
1244        required = fptr->common.required_num_args;
1245        for (i = 0; i < fptr->common.num_args;) {
1246            if (arg_info->class_name) {
1247                const char *class_name;
1248                uint32_t class_name_len;
1249                if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
1250                    class_name = fptr->common.scope->name->val;
1251                    class_name_len = fptr->common.scope->name->len;
1252                } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
1253                    class_name = fptr->common.scope->parent->name->val;
1254                    class_name_len = fptr->common.scope->parent->name->len;
1255                } else {
1256                    class_name = arg_info->class_name;
1257                    class_name_len = arg_info->class_name_len;
1258                }
1259                REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
1260                memcpy(offset, class_name, class_name_len);
1261                offset += class_name_len;
1262                *(offset++) = ' ';
1263            } else if (arg_info->type_hint) {
1264                uint32_t type_name_len;
1265                char *type_name = zend_get_type_by_const(arg_info->type_hint);
1266                type_name_len = strlen(type_name);
1267                REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
1268                memcpy(offset, type_name, type_name_len);
1269                offset += type_name_len;
1270                *(offset++) = ' ';
1271            }
1272
1273            if (arg_info->pass_by_reference) {
1274                *(offset++) = '&';
1275            }
1276
1277            if (arg_info->is_variadic) {
1278                *(offset++) = '.';
1279                *(offset++) = '.';
1280                *(offset++) = '.';
1281            }
1282
1283            *(offset++) = '$';
1284
1285            if (arg_info->name) {
1286                REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
1287                memcpy(offset, arg_info->name, arg_info->name_len);
1288                offset += arg_info->name_len;
1289            } else {
1290                uint32_t idx = i;
1291                memcpy(offset, "param", 5);
1292                offset += 5;
1293                do {
1294                    *(offset++) = (char) (idx % 10) + '0';
1295                    idx /= 10;
1296                } while (idx > 0);
1297            }
1298            if (i >= required && !arg_info->is_variadic) {
1299                *(offset++) = ' ';
1300                *(offset++) = '=';
1301                *(offset++) = ' ';
1302                if (fptr->type == ZEND_USER_FUNCTION) {
1303                    zend_op *precv = NULL;
1304                    {
1305                        uint32_t idx  = i;
1306                        zend_op *op = ((zend_op_array *)fptr)->opcodes;
1307                        zend_op *end = op + ((zend_op_array *)fptr)->last;
1308
1309                        ++idx;
1310                        while (op < end) {
1311                            if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
1312                                    && op->op1.num == (zend_ulong)idx)
1313                            {
1314                                precv = op;
1315                            }
1316                            ++op;
1317                        }
1318                    }
1319                    if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
1320                        zval *zv = precv->op2.zv;
1321
1322                        if (Z_TYPE_P(zv) == IS_CONSTANT) {
1323                            REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
1324                            memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
1325                            offset += Z_STRLEN_P(zv);
1326                        } else if (Z_TYPE_P(zv) == IS_FALSE) {
1327                            memcpy(offset, "false", 5);
1328                            offset += 5;
1329                        } else if (Z_TYPE_P(zv) == IS_TRUE) {
1330                            memcpy(offset, "true", 4);
1331                            offset += 4;
1332                        } else if (Z_TYPE_P(zv) == IS_NULL) {
1333                            memcpy(offset, "NULL", 4);
1334                            offset += 4;
1335                        } else if (Z_TYPE_P(zv) == IS_STRING) {
1336                            *(offset++) = '\'';
1337                            REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
1338                            memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
1339                            offset += MIN(Z_STRLEN_P(zv), 10);
1340                            if (Z_STRLEN_P(zv) > 10) {
1341                                *(offset++) = '.';
1342                                *(offset++) = '.';
1343                                *(offset++) = '.';
1344                            }
1345                            *(offset++) = '\'';
1346                        } else if (Z_TYPE_P(zv) == IS_ARRAY) {
1347                            memcpy(offset, "Array", 5);
1348                            offset += 5;
1349                        } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1350                            memcpy(offset, "<expression>", 12);
1351                            offset += 12;
1352                        } else {
1353                            zend_string *str = zval_get_string(zv);
1354                            REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len);
1355                            memcpy(offset, str->val, str->len);
1356                            offset += str->len;
1357                            zend_string_release(str);
1358                        }
1359                    }
1360                } else {
1361                    memcpy(offset, "NULL", 4);
1362                    offset += 4;
1363                }
1364            }
1365
1366            if (++i < fptr->common.num_args) {
1367                *(offset++) = ',';
1368                *(offset++) = ' ';
1369            }
1370            arg_info++;
1371            REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
1372        }
1373    }
1374    *(offset++) = ')';
1375    *offset = '\0';
1376
1377    return buf;
1378}
1379/* }}} */
1380
1381static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
1382{
1383    uint32_t child_flags;
1384    uint32_t parent_flags = parent->common.fn_flags;
1385
1386    if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
1387        && parent->common.fn_flags & ZEND_ACC_ABSTRACT
1388        && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
1389        && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
1390        zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
1391            parent->common.scope->name->val,
1392            child->common.function_name->val,
1393            child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val);
1394    }
1395
1396    if (parent_flags & ZEND_ACC_FINAL) {
1397        zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val);
1398    }
1399
1400    child_flags = child->common.fn_flags;
1401    /* You cannot change from static to non static and vice versa.
1402     */
1403    if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
1404        if (child->common.fn_flags & ZEND_ACC_STATIC) {
1405            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));
1406        } else {
1407            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));
1408        }
1409    }
1410
1411    /* Disallow making an inherited method abstract. */
1412    if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
1413        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));
1414    }
1415
1416    if (parent_flags & ZEND_ACC_CHANGED) {
1417        child->common.fn_flags |= ZEND_ACC_CHANGED;
1418    } else {
1419        /* Prevent derived classes from restricting access that was available in parent classes
1420         */
1421        if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1422            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");
1423        } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
1424            && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
1425            child->common.fn_flags |= ZEND_ACC_CHANGED;
1426        }
1427    }
1428
1429    if (parent_flags & ZEND_ACC_PRIVATE) {
1430        child->common.prototype = NULL;
1431    } else if (parent_flags & ZEND_ACC_ABSTRACT) {
1432        child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
1433        child->common.prototype = parent;
1434    } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
1435        /* ctors only have a prototype if it comes from an interface */
1436        child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1437    }
1438
1439    if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1440        if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
1441            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));
1442        }
1443    } 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 */
1444        if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
1445            char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
1446            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);
1447            efree(method_prototype);
1448        }
1449    }
1450}
1451/* }}} */
1452
1453static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, zend_string *key, zend_class_entry *child_ce) /* {{{ */
1454{
1455    uint32_t parent_flags = parent->common.fn_flags;
1456    zend_function *child;
1457    TSRMLS_FETCH();
1458
1459    if ((child = zend_hash_find_ptr(child_function_table, key)) == NULL) {
1460        if (parent_flags & (ZEND_ACC_ABSTRACT)) {
1461            child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1462        }
1463        return 1; /* method doesn't exist in child, copy from parent */
1464    }
1465
1466    do_inheritance_check_on_method(child, parent TSRMLS_CC);
1467
1468    return 0;
1469}
1470/* }}} */
1471
1472static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, zend_string *key, zend_class_entry *ce TSRMLS_DC) /* {{{ */
1473{
1474    zend_property_info *child_info;
1475    zend_class_entry *parent_ce = ce->parent;
1476
1477    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
1478        if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
1479            child_info->flags |= ZEND_ACC_CHANGED;
1480        } else {
1481            if(ce->type & ZEND_INTERNAL_CLASS) {
1482                child_info = zend_duplicate_property_info_internal(parent_info);
1483            } else {
1484                child_info = zend_duplicate_property_info(parent_info TSRMLS_CC);
1485            }
1486            zend_hash_update_ptr(&ce->properties_info, key, child_info);
1487            child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
1488            child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
1489        }
1490        return 0; /* don't copy access information to child */
1491    }
1492
1493    if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
1494        if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
1495            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1496                (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val,
1497                (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val);
1498
1499        }
1500
1501        if(parent_info->flags & ZEND_ACC_CHANGED) {
1502            child_info->flags |= ZEND_ACC_CHANGED;
1503        }
1504
1505        if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
1506            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");
1507        } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
1508            zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
1509            ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
1510            ZVAL_UNDEF(&ce->default_properties_table[child_info->offset]);
1511            child_info->offset = parent_info->offset;
1512        }
1513        return 0;   /* Don't copy from parent */
1514    } else {
1515        return 1;   /* Copy from parent */
1516    }
1517}
1518/* }}} */
1519
1520static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1521{
1522    if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
1523        zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name->val, iface->name->val);
1524    }
1525    if (ce == iface) {
1526        zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name->val);
1527    }
1528}
1529/* }}} */
1530
1531ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
1532{
1533    /* expects interface to be contained in ce's interface list already */
1534    uint32_t i, ce_num, if_num = iface->num_interfaces;
1535    zend_class_entry *entry;
1536
1537    if (if_num==0) {
1538        return;
1539    }
1540    ce_num = ce->num_interfaces;
1541
1542    if (ce->type == ZEND_INTERNAL_CLASS) {
1543        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1544    } else {
1545        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1546    }
1547
1548    /* Inherit the interfaces, only if they're not already inherited by the class */
1549    while (if_num--) {
1550        entry = iface->interfaces[if_num];
1551        for (i = 0; i < ce_num; i++) {
1552            if (ce->interfaces[i] == entry) {
1553                break;
1554            }
1555        }
1556        if (i == ce_num) {
1557            ce->interfaces[ce->num_interfaces++] = entry;
1558        }
1559    }
1560
1561    /* and now call the implementing handlers */
1562    while (ce_num < ce->num_interfaces) {
1563        do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
1564    }
1565}
1566/* }}} */
1567
1568#ifdef ZTS
1569# define zval_property_ctor(parent_ce, ce) \
1570    (((parent_ce)->type != (ce)->type) ? ZVAL_COPY_CTOR : zval_add_ref)
1571#else
1572# define zval_property_ctor(parent_ce, ce) \
1573    zval_add_ref
1574#endif
1575
1576static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
1577{
1578    if (!Z_ISREF_P(zv)) {
1579        if (parent_ce->type == ZEND_INTERNAL_CLASS) {
1580            ZVAL_NEW_PERSISTENT_REF(zv, zv);
1581        } else {
1582            ZVAL_NEW_REF(zv, zv);
1583        }
1584    }
1585    if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
1586        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1587    }
1588    if (zend_hash_add(&ce->constants_table, name, zv)) {
1589        Z_ADDREF_P(zv);
1590    }
1591}
1592/* }}} */
1593
1594ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
1595{
1596    zend_property_info *property_info;
1597    zend_function *func;
1598    zend_string *key;
1599    zval *zv;
1600
1601    if ((ce->ce_flags & ZEND_ACC_INTERFACE)
1602        && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
1603        zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val);
1604    }
1605    if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
1606        zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val);
1607    }
1608
1609    ce->parent = parent_ce;
1610    /* Copy serialize/unserialize callbacks */
1611    if (!ce->serialize) {
1612        ce->serialize   = parent_ce->serialize;
1613    }
1614    if (!ce->unserialize) {
1615        ce->unserialize = parent_ce->unserialize;
1616    }
1617
1618    /* Inherit interfaces */
1619    zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
1620
1621    /* Inherit properties */
1622    if (parent_ce->default_properties_count) {
1623        int i = ce->default_properties_count + parent_ce->default_properties_count;
1624
1625        ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
1626        if (ce->default_properties_count) {
1627            while (i-- > parent_ce->default_properties_count) {
1628                ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
1629            }
1630        }
1631        for (i = 0; i < parent_ce->default_properties_count; i++) {
1632#ifdef ZTS
1633            if (parent_ce->type != ce->type) {
1634                ZVAL_DUP(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
1635                if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
1636                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1637                }
1638                continue;
1639            }
1640#endif
1641
1642            ZVAL_COPY(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
1643            if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
1644                ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1645            }
1646        }
1647        ce->default_properties_count += parent_ce->default_properties_count;
1648    }
1649
1650    if (parent_ce->type != ce->type) {
1651        /* User class extends internal class */
1652        zend_update_class_constants(parent_ce  TSRMLS_CC);
1653        if (parent_ce->default_static_members_count) {
1654            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
1655
1656            ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(zval) * i);
1657            if (ce->default_static_members_count) {
1658                while (i-- > parent_ce->default_static_members_count) {
1659                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
1660                }
1661            }
1662            for (i = 0; i < parent_ce->default_static_members_count; i++) {
1663                ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
1664                ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
1665                Z_ADDREF(ce->default_static_members_table[i]);
1666                if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
1667                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1668                }
1669            }
1670            ce->default_static_members_count += parent_ce->default_static_members_count;
1671            ce->static_members_table = ce->default_static_members_table;
1672        }
1673    } else {
1674        if (parent_ce->default_static_members_count) {
1675            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
1676
1677            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
1678            if (ce->default_static_members_count) {
1679                while (i-- > parent_ce->default_static_members_count) {
1680                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
1681                }
1682            }
1683            for (i = 0; i < parent_ce->default_static_members_count; i++) {
1684                ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
1685                ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
1686                Z_ADDREF(ce->default_static_members_table[i]);
1687                if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
1688                    ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1689                }
1690            }
1691            ce->default_static_members_count += parent_ce->default_static_members_count;
1692            if (ce->type == ZEND_USER_CLASS) {
1693                ce->static_members_table = ce->default_static_members_table;
1694            }
1695        }
1696    }
1697
1698    ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
1699        if (property_info->ce == ce) {
1700            if (property_info->flags & ZEND_ACC_STATIC) {
1701                property_info->offset += parent_ce->default_static_members_count;
1702            } else {
1703                property_info->offset += parent_ce->default_properties_count;
1704            }
1705        }
1706    } ZEND_HASH_FOREACH_END();
1707
1708    ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1709        if (do_inherit_property_access_check(&ce->properties_info, property_info, key, ce TSRMLS_CC)) {
1710            if (ce->type & ZEND_INTERNAL_CLASS) {
1711                property_info = zend_duplicate_property_info_internal(property_info);
1712            } else {
1713                property_info = zend_duplicate_property_info(property_info TSRMLS_CC);
1714            }
1715            zend_hash_add_new_ptr(&ce->properties_info, key, property_info);
1716        }
1717    } ZEND_HASH_FOREACH_END();
1718
1719    ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
1720        do_inherit_class_constant(key, zv, ce, parent_ce TSRMLS_CC);
1721    } ZEND_HASH_FOREACH_END();
1722
1723    ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1724        if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
1725            zend_function *new_func = do_inherit_method(func TSRMLS_CC);
1726            zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1727        }
1728    } ZEND_HASH_FOREACH_END();
1729
1730    do_inherit_parent_constructor(ce TSRMLS_CC);
1731
1732    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
1733        ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1734    } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
1735        /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
1736        zend_verify_abstract_class(ce TSRMLS_CC);
1737    }
1738    ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
1739}
1740/* }}} */
1741
1742static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
1743{
1744    zval *old_constant;
1745
1746    if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
1747        if (!Z_ISREF_P(old_constant) ||
1748            !Z_ISREF_P(parent_constant) ||
1749            Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
1750            zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", name->val, iface->name->val);
1751        }
1752        return 0;
1753    }
1754    return 1;
1755}
1756/* }}} */
1757
1758static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1759{
1760    if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
1761        ZVAL_MAKE_REF(zv);
1762        Z_ADDREF_P(zv);
1763        if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
1764            ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1765        }
1766        zend_hash_update(&ce->constants_table, name, zv);
1767    }
1768}
1769/* }}} */
1770
1771ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
1772{
1773    uint32_t i, ignore = 0;
1774    uint32_t current_iface_num = ce->num_interfaces;
1775    uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
1776    zend_function *func;
1777    zend_string *key;
1778    zval *zv;
1779
1780    for (i = 0; i < ce->num_interfaces; i++) {
1781        if (ce->interfaces[i] == NULL) {
1782            memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1783            i--;
1784        } else if (ce->interfaces[i] == iface) {
1785            if (i < parent_iface_num) {
1786                ignore = 1;
1787            } else {
1788                zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name->val, iface->name->val);
1789            }
1790        }
1791    }
1792    if (ignore) {
1793        /* Check for attempt to redeclare interface constants */
1794        ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
1795            do_inherit_constant_check(&iface->constants_table, zv, key, iface);
1796        } ZEND_HASH_FOREACH_END();
1797    } else {
1798        if (ce->num_interfaces >= current_iface_num) {
1799            if (ce->type == ZEND_INTERNAL_CLASS) {
1800                ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1801            } else {
1802                ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1803            }
1804        }
1805        ce->interfaces[ce->num_interfaces++] = iface;
1806
1807        ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
1808            do_inherit_iface_constant(key, zv, ce, iface TSRMLS_CC);
1809        } ZEND_HASH_FOREACH_END();
1810
1811        ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1812            if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
1813                zend_function *new_func = do_inherit_method(func TSRMLS_CC);
1814                zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1815            }
1816        } ZEND_HASH_FOREACH_END();
1817
1818        do_implement_interface(ce, iface TSRMLS_CC);
1819        zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
1820    }
1821}
1822/* }}} */
1823
1824ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
1825{
1826    uint32_t i, ignore = 0;
1827    uint32_t current_trait_num = ce->num_traits;
1828    uint32_t parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
1829
1830    for (i = 0; i < ce->num_traits; i++) {
1831        if (ce->traits[i] == NULL) {
1832            memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
1833            i--;
1834        } else if (ce->traits[i] == trait) {
1835            if (i < parent_trait_num) {
1836                ignore = 1;
1837            }
1838        }
1839    }
1840    if (!ignore) {
1841        if (ce->num_traits >= current_trait_num) {
1842            if (ce->type == ZEND_INTERNAL_CLASS) {
1843                ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1844            } else {
1845                ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1846            }
1847        }
1848        ce->traits[ce->num_traits++] = trait;
1849    }
1850}
1851/* }}} */
1852
1853static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
1854{
1855    uint32_t    fn_flags = fn->common.scope->ce_flags;
1856    uint32_t other_flags = other_fn->common.scope->ce_flags;
1857
1858    return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
1859        && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
1860        && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
1861            (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
1862}
1863/* }}} */
1864
1865static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe TSRMLS_DC) /* {{{ */
1866{
1867    if (!strncmp(mname->val, ZEND_CLONE_FUNC_NAME, mname->len)) {
1868        ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
1869    } else if (!strncmp(mname->val, ZEND_CONSTRUCTOR_FUNC_NAME, mname->len)) {
1870        if (ce->constructor) {
1871            zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
1872        }
1873        ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
1874    } else if (!strncmp(mname->val, ZEND_DESTRUCTOR_FUNC_NAME,  mname->len)) {
1875        ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
1876    } else if (!strncmp(mname->val, ZEND_GET_FUNC_NAME, mname->len)) {
1877        ce->__get = fe;
1878    } else if (!strncmp(mname->val, ZEND_SET_FUNC_NAME, mname->len)) {
1879        ce->__set = fe;
1880    } else if (!strncmp(mname->val, ZEND_CALL_FUNC_NAME, mname->len)) {
1881        ce->__call = fe;
1882    } else if (!strncmp(mname->val, ZEND_UNSET_FUNC_NAME, mname->len)) {
1883        ce->__unset = fe;
1884    } else if (!strncmp(mname->val, ZEND_ISSET_FUNC_NAME, mname->len)) {
1885        ce->__isset = fe;
1886    } else if (!strncmp(mname->val, ZEND_CALLSTATIC_FUNC_NAME, mname->len)) {
1887        ce->__callstatic = fe;
1888    } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) {
1889        ce->__tostring = fe;
1890    } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) {
1891        ce->__debugInfo = fe;
1892    } else if (ce->name->len == mname->len) {
1893        zend_string *lowercase_name = zend_string_alloc(ce->name->len, 0);
1894        zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len);
1895        lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
1896        if (!memcmp(mname->val, lowercase_name->val, mname->len)) {
1897            if (ce->constructor) {
1898                zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
1899            }
1900            ce->constructor = fe;
1901            fe->common.fn_flags |= ZEND_ACC_CTOR;
1902        }
1903        zend_string_release(lowercase_name);
1904    }
1905}
1906/* }}} */
1907
1908static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
1909{
1910    zend_function *existing_fn = NULL;
1911    zend_function *new_fn;
1912
1913    if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1914        if (existing_fn->common.scope == ce) {
1915            /* members from the current class override trait methods */
1916            /* use temporary *overriden HashTable to detect hidden conflict */
1917            if (*overriden) {
1918                if ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
1919                    if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1920                        /* Make sure the trait method is compatible with previosly declared abstract method */
1921                        if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
1922                            zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1923                                zend_get_function_declaration(fn TSRMLS_CC),
1924                                zend_get_function_declaration(existing_fn TSRMLS_CC));
1925                        }
1926                    } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1927                        /* Make sure the abstract declaration is compatible with previous declaration */
1928                        if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
1929                            zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1930                                zend_get_function_declaration(fn TSRMLS_CC),
1931                                zend_get_function_declaration(existing_fn TSRMLS_CC));
1932                        }
1933                        return;
1934                    }
1935                }
1936            } else {
1937                ALLOC_HASHTABLE(*overriden);
1938                zend_hash_init_ex(*overriden, 8, NULL, ptr_dtor, 0, 0);
1939            }
1940            zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
1941            return;
1942        } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1943            /* Make sure the trait method is compatible with previosly declared abstract method */
1944            if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
1945                zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1946                    zend_get_function_declaration(fn TSRMLS_CC),
1947                    zend_get_function_declaration(existing_fn TSRMLS_CC));
1948            }
1949        } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1950            /* Make sure the abstract declaration is compatible with previous declaration */
1951            if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
1952                zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1953                    zend_get_function_declaration(fn TSRMLS_CC),
1954                    zend_get_function_declaration(existing_fn TSRMLS_CC));
1955            }
1956            return;
1957        } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1958            /* two traits can't define the same non-abstract method */
1959#if 1
1960            zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
1961                name, ce->name->val);
1962#else       /* TODO: better error message */
1963            zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1964                fn->common.scope->name->val, fn->common.function_name->val,
1965                ce->name->val, name,
1966                existing_fn->common.scope->name->val, existing_fn->common.function_name->val);
1967#endif
1968        } else {
1969            /* inherited members are overridden by members inserted by traits */
1970            /* check whether the trait method fulfills the inheritance requirements */
1971            do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
1972        }
1973    }
1974
1975    function_add_ref(fn);
1976    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1977    memcpy(new_fn, fn, sizeof(zend_op_array));
1978    fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1979    zend_add_magic_methods(ce, key, fn TSRMLS_CC);
1980}
1981/* }}} */
1982
1983static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1984{
1985    if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1986
1987        fn->common.scope = ce;
1988
1989        if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1990            ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1991        }
1992        if (fn->op_array.static_variables) {
1993            ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1994        }
1995    }
1996}
1997/* }}} */
1998
1999static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table TSRMLS_DC) /* {{{ */
2000{
2001    zend_trait_alias  *alias, **alias_ptr;
2002    zend_string       *lcname;
2003    zend_function      fn_copy;
2004
2005    /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2006    if (ce->trait_aliases) {
2007        alias_ptr = ce->trait_aliases;
2008        alias = *alias_ptr;
2009        while (alias) {
2010            /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2011            if (alias->alias != NULL
2012                && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
2013                && alias->trait_method->method_name->len == fnname->len
2014                && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
2015                fn_copy = *fn;
2016
2017                /* if it is 0, no modifieres has been changed */
2018                if (alias->modifiers) {
2019                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
2020                }
2021
2022                lcname = zend_string_alloc(alias->alias->len, 0);
2023                zend_str_tolower_copy(lcname->val, alias->alias->val, alias->alias->len);
2024                zend_add_trait_method(ce, alias->alias->val, lcname, &fn_copy, overriden TSRMLS_CC);
2025                zend_string_release(lcname);
2026
2027                /* Record the trait from which this alias was resolved. */
2028                if (!alias->trait_method->ce) {
2029                    alias->trait_method->ce = fn->common.scope;
2030                }
2031            }
2032            alias_ptr++;
2033            alias = *alias_ptr;
2034        }
2035    }
2036
2037    if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2038        /* is not in hashtable, thus, function is not to be excluded */
2039        fn_copy = *fn;
2040
2041        /* apply aliases which have not alias name, just setting visibility */
2042        if (ce->trait_aliases) {
2043            alias_ptr = ce->trait_aliases;
2044            alias = *alias_ptr;
2045            while (alias) {
2046                /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2047                if (alias->alias == NULL && alias->modifiers != 0
2048                    && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
2049                    && (alias->trait_method->method_name->len == fnname->len)
2050                    && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
2051
2052                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
2053
2054                    /** Record the trait from which this alias was resolved. */
2055                    if (!alias->trait_method->ce) {
2056                        alias->trait_method->ce = fn->common.scope;
2057                    }
2058                }
2059                alias_ptr++;
2060                alias = *alias_ptr;
2061            }
2062        }
2063
2064        zend_add_trait_method(ce, fn->common.function_name->val, fnname, &fn_copy, overriden TSRMLS_CC);
2065    }
2066
2067    return ZEND_HASH_APPLY_KEEP;
2068}
2069/* }}} */
2070
2071static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
2072{
2073    uint32_t i;
2074
2075    if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
2076        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);
2077    }
2078
2079    for (i = 0; i < ce->num_traits; i++) {
2080        if (ce->traits[i] == trait) {
2081            return;
2082        }
2083    }
2084    zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name->val, ce->name->val);
2085}
2086/* }}} */
2087
2088static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2089{
2090    size_t i, j = 0;
2091    zend_trait_precedence *cur_precedence;
2092    zend_trait_method_reference *cur_method_ref;
2093    zend_string *lcname;
2094    zend_bool method_exists;
2095
2096    /* resolve class references */
2097    if (ce->trait_precedences) {
2098        i = 0;
2099        while ((cur_precedence = ce->trait_precedences[i])) {
2100            /** Resolve classes for all precedence operations. */
2101            if (cur_precedence->exclude_from_classes) {
2102                cur_method_ref = cur_precedence->trait_method;
2103                if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
2104                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2105                    zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
2106                }
2107                zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
2108
2109                /** Ensure that the prefered method is actually available. */
2110                lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
2111                zend_str_tolower_copy(lcname->val,
2112                    cur_method_ref->method_name->val,
2113                    cur_method_ref->method_name->len);
2114                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
2115                                                 lcname);
2116                zend_string_free(lcname);
2117                if (!method_exists) {
2118                    zend_error_noreturn(E_COMPILE_ERROR,
2119                               "A precedence rule was defined for %s::%s but this method does not exist",
2120                               cur_method_ref->ce->name->val,
2121                               cur_method_ref->method_name->val);
2122                }
2123
2124                /** With the other traits, we are more permissive.
2125                    We do not give errors for those. This allows to be more
2126                    defensive in such definitions.
2127                    However, we want to make sure that the insteadof declaration
2128                    is consistent in itself.
2129                 */
2130                j = 0;
2131                while (cur_precedence->exclude_from_classes[j].class_name) {
2132                    zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
2133
2134                    if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2135                        zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", class_name->val);
2136                    }
2137                    zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce TSRMLS_CC);
2138
2139                    /* make sure that the trait method is not from a class mentioned in
2140                     exclude_from_classes, for consistency */
2141                    if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i].ce) {
2142                        zend_error_noreturn(E_COMPILE_ERROR,
2143                                   "Inconsistent insteadof definition. "
2144                                   "The method %s is to be used from %s, but %s is also on the exclude list",
2145                                   cur_method_ref->method_name->val,
2146                                   cur_precedence->trait_method->ce->name->val,
2147                                   cur_precedence->trait_method->ce->name->val);
2148                    }
2149
2150                    zend_string_release(class_name);
2151                    j++;
2152                }
2153            }
2154            i++;
2155        }
2156    }
2157
2158    if (ce->trait_aliases) {
2159        i = 0;
2160        while (ce->trait_aliases[i]) {
2161            /** For all aliases with an explicit class name, resolve the class now. */
2162            if (ce->trait_aliases[i]->trait_method->class_name) {
2163                cur_method_ref = ce->trait_aliases[i]->trait_method;
2164                if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
2165                    zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
2166                }
2167                zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
2168
2169                /** And, ensure that the referenced method is resolvable, too. */
2170                lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
2171                zend_str_tolower_copy(lcname->val,
2172                    cur_method_ref->method_name->val,
2173                    cur_method_ref->method_name->len);
2174                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
2175                        lcname);
2176                zend_string_free(lcname);
2177
2178                if (!method_exists) {
2179                    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);
2180                }
2181            }
2182            i++;
2183        }
2184    }
2185}
2186/* }}} */
2187
2188static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
2189{
2190    size_t i = 0, j;
2191
2192    if (!precedences) {
2193        return;
2194    }
2195    while (precedences[i]) {
2196        if (precedences[i]->exclude_from_classes) {
2197            j = 0;
2198            while (precedences[i]->exclude_from_classes[j].ce) {
2199                if (precedences[i]->exclude_from_classes[j].ce == trait) {
2200                    zend_string *lcname = zend_string_alloc(precedences[i]->trait_method->method_name->len, 0);
2201
2202                    zend_str_tolower_copy(lcname->val,
2203                        precedences[i]->trait_method->method_name->val,
2204                        precedences[i]->trait_method->method_name->len);
2205                    if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
2206                        zend_string_release(lcname);
2207                        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);
2208                    }
2209                    zend_string_release(lcname);
2210                }
2211                ++j;
2212            }
2213        }
2214        ++i;
2215    }
2216}
2217/* }}} */
2218
2219static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2220{
2221    uint32_t i;
2222    HashTable *overriden = NULL;
2223    zend_string *key;
2224    zend_function *fn;
2225
2226    for (i = 0; i < ce->num_traits; i++) {
2227        if (ce->trait_precedences) {
2228            HashTable exclude_table;
2229
2230            /* TODO: revisit this start size, may be its not optimal */
2231            zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
2232
2233            zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
2234
2235            /* copies functions, applies defined aliasing, and excludes unused trait methods */
2236            ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
2237                zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table TSRMLS_CC);
2238            } ZEND_HASH_FOREACH_END();
2239
2240            zend_hash_destroy(&exclude_table);
2241        } else {
2242            ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
2243                zend_traits_copy_functions(key, fn, ce, &overriden, NULL TSRMLS_CC);
2244            } ZEND_HASH_FOREACH_END();
2245        }
2246    }
2247
2248    ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
2249        zend_fixup_trait_method(fn, ce);
2250    } ZEND_HASH_FOREACH_END();
2251
2252    if (overriden) {
2253        zend_hash_destroy(overriden);
2254        FREE_HASHTABLE(overriden);
2255    }
2256}
2257/* }}} */
2258
2259static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
2260{
2261    size_t i;
2262
2263    if (coliding_ce == ce) {
2264        for (i = 0; i < current_trait; i++) {
2265            if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
2266                return ce->traits[i];
2267            }
2268        }
2269    }
2270
2271    return coliding_ce;
2272}
2273/* }}} */
2274
2275static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2276{
2277    size_t i;
2278    zend_property_info *property_info;
2279    zend_property_info *coliding_prop;
2280    zval compare_result;
2281    zend_string* prop_name;
2282    const char* class_name_unused;
2283    zend_bool not_compatible;
2284    zval* prop_value;
2285    uint32_t flags;
2286    zend_string *doc_comment;
2287
2288    /* In the following steps the properties are inserted into the property table
2289     * for that, a very strict approach is applied:
2290     * - check for compatibility, if not compatible with any property in class -> fatal
2291     * - if compatible, then strict notice
2292     */
2293    for (i = 0; i < ce->num_traits; i++) {
2294        ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
2295            /* first get the unmangeld name if necessary,
2296             * then check whether the property is already there
2297             */
2298            flags = property_info->flags;
2299            if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
2300                prop_name = zend_string_copy(property_info->name);
2301            } else {
2302                const char *pname;
2303                size_t pname_len;
2304
2305                /* for private and protected we need to unmangle the names */
2306                zend_unmangle_property_name_ex(property_info->name,
2307                                            &class_name_unused, &pname, &pname_len);
2308                prop_name = zend_string_init(pname, pname_len, 0);
2309            }
2310
2311            /* next: check for conflicts with current class */
2312            if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2313                if (coliding_prop->flags & ZEND_ACC_SHADOW) {
2314                    zend_hash_del(&ce->properties_info, prop_name);
2315                    flags |= ZEND_ACC_CHANGED;
2316                } else {
2317                    if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
2318                        == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
2319                        /* flags are identical, now the value needs to be checked */
2320                        if (flags & ZEND_ACC_STATIC) {
2321                            not_compatible = (FAILURE == compare_function(&compare_result,
2322                                              &ce->default_static_members_table[coliding_prop->offset],
2323                                              &ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
2324                                  || (Z_LVAL(compare_result) != 0);
2325                        } else {
2326                            not_compatible = (FAILURE == compare_function(&compare_result,
2327                                              &ce->default_properties_table[coliding_prop->offset],
2328                                              &ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
2329                                  || (Z_LVAL(compare_result) != 0);
2330                        }
2331                    } else {
2332                        /* the flags are not identical, thus, we assume properties are not compatible */
2333                        not_compatible = 1;
2334                    }
2335
2336                    if (not_compatible) {
2337                        zend_error_noreturn(E_COMPILE_ERROR,
2338                               "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2339                                find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
2340                                property_info->ce->name->val,
2341                                prop_name->val,
2342                                ce->name->val);
2343                    } else {
2344                        zend_error(E_STRICT,
2345                               "%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",
2346                                find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
2347                                property_info->ce->name->val,
2348                                prop_name->val,
2349                                ce->name->val);
2350                        zend_string_release(prop_name);
2351                        continue;
2352                    }
2353                }
2354            }
2355
2356            /* property not found, so lets add it */
2357            if (flags & ZEND_ACC_STATIC) {
2358                prop_value = &ce->traits[i]->default_static_members_table[property_info->offset];
2359            } else {
2360                prop_value = &ce->traits[i]->default_properties_table[property_info->offset];
2361            }
2362            if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
2363
2364            doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2365            zend_declare_property_ex(ce, prop_name,
2366                                     prop_value, flags,
2367                                     doc_comment TSRMLS_CC);
2368            zend_string_release(prop_name);
2369        } ZEND_HASH_FOREACH_END();
2370    }
2371}
2372/* }}} */
2373
2374static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2375{
2376    int i = 0;
2377    zend_trait_alias* cur_alias;
2378    zend_string* lc_method_name;
2379
2380    if (ce->trait_aliases) {
2381        while (ce->trait_aliases[i]) {
2382            cur_alias = ce->trait_aliases[i];
2383            /** The trait for this alias has not been resolved, this means, this
2384                alias was not applied. Abort with an error. */
2385            if (!cur_alias->trait_method->ce) {
2386                if (cur_alias->alias) {
2387                    /** Plain old inconsistency/typo/bug */
2388                    zend_error_noreturn(E_COMPILE_ERROR,
2389                               "An alias (%s) was defined for method %s(), but this method does not exist",
2390                               cur_alias->alias->val,
2391                               cur_alias->trait_method->method_name->val);
2392                } else {
2393                    /** Here are two possible cases:
2394                        1) this is an attempt to modifiy the visibility
2395                           of a method introduce as part of another alias.
2396                           Since that seems to violate the DRY principle,
2397                           we check against it and abort.
2398                        2) it is just a plain old inconsitency/typo/bug
2399                           as in the case where alias is set. */
2400
2401                    lc_method_name = zend_string_alloc(cur_alias->trait_method->method_name->len, 0);
2402                    zend_str_tolower_copy(
2403                        lc_method_name->val,
2404                        cur_alias->trait_method->method_name->val,
2405                        cur_alias->trait_method->method_name->len);
2406                    if (zend_hash_exists(&ce->function_table,
2407                                         lc_method_name)) {
2408                        zend_string_free(lc_method_name);
2409                        zend_error_noreturn(E_COMPILE_ERROR,
2410                                   "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
2411                                   cur_alias->trait_method->method_name->val);
2412                    } else {
2413                        zend_string_free(lc_method_name);
2414                        zend_error_noreturn(E_COMPILE_ERROR,
2415                                   "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2416                                   cur_alias->trait_method->method_name->val);
2417
2418                    }
2419                }
2420            }
2421            i++;
2422        }
2423    }
2424}
2425/* }}} */
2426
2427ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
2428{
2429
2430    if (ce->num_traits <= 0) {
2431        return;
2432    }
2433
2434    /* complete initialization of trait strutures in ce */
2435    zend_traits_init_trait_structures(ce TSRMLS_CC);
2436
2437    /* first care about all methods to be flattened into the class */
2438    zend_do_traits_method_binding(ce TSRMLS_CC);
2439
2440    /* Aliases which have not been applied indicate typos/bugs. */
2441    zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
2442
2443    /* then flatten the properties into it, to, mostly to notfiy developer about problems */
2444    zend_do_traits_property_binding(ce TSRMLS_CC);
2445
2446    /* verify that all abstract methods from traits have been implemented */
2447    zend_verify_abstract_class(ce TSRMLS_CC);
2448
2449    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
2450    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
2451        ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2452    }
2453}
2454/* }}} */
2455
2456ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
2457{
2458    zend_function *function, *new_function;
2459    zval *op1, *op2;
2460
2461    if (compile_time) {
2462        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2463        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2464    } else {
2465        op1 = opline->op1.zv;
2466        op2 = opline->op2.zv;
2467    }
2468
2469    function = zend_hash_find_ptr(function_table, Z_STR_P(op1));
2470    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2471    memcpy(new_function, function, sizeof(zend_op_array));
2472    if (zend_hash_add_ptr(function_table, Z_STR_P(op2), new_function) == NULL) {
2473        int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
2474        zend_function *old_function;
2475
2476        efree_size(new_function, sizeof(zend_op_array));
2477        if ((old_function = zend_hash_find_ptr(function_table, Z_STR_P(op2))) != NULL
2478            && old_function->type == ZEND_USER_FUNCTION
2479            && old_function->op_array.last > 0) {
2480            zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
2481                        function->common.function_name->val,
2482                        old_function->op_array.filename->val,
2483                        old_function->op_array.opcodes[0].lineno);
2484        } else {
2485            zend_error(error_level, "Cannot redeclare %s()", function->common.function_name->val);
2486        }
2487        return FAILURE;
2488    } else {
2489        (*function->op_array.refcount)++;
2490        function->op_array.static_variables = NULL; /* NULL out the unbound function */
2491        return SUCCESS;
2492    }
2493}
2494/* }}} */
2495
2496ZEND_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) /* {{{ */
2497{
2498    zend_class_entry *ce;
2499    zval *op1, *op2;
2500
2501    if (compile_time) {
2502        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2503        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2504    } else {
2505        op1 = opline->op1.zv;
2506        op2 = opline->op2.zv;
2507    }
2508    if ((ce = zend_hash_find_ptr(class_table, Z_STR_P(op1))) == NULL) {
2509        zend_error_noreturn(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
2510        return NULL;
2511    }
2512    ce->refcount++;
2513    if (zend_hash_add_ptr(class_table, Z_STR_P(op2), ce) == NULL) {
2514        ce->refcount--;
2515        if (!compile_time) {
2516            /* If we're in compile time, in practice, it's quite possible
2517             * that we'll never reach this class declaration at runtime,
2518             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
2519             * approach to work.
2520             */
2521            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name->val);
2522        }
2523        return NULL;
2524    } else {
2525        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
2526            zend_verify_abstract_class(ce TSRMLS_CC);
2527        }
2528        return ce;
2529    }
2530}
2531/* }}} */
2532
2533ZEND_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) /* {{{ */
2534{
2535    zend_class_entry *ce;
2536    zval *op1, *op2;
2537
2538    if (compile_time) {
2539        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
2540        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
2541    } else {
2542        op1 = opline->op1.zv;
2543        op2 = opline->op2.zv;
2544    }
2545
2546    ce = zend_hash_find_ptr(class_table, Z_STR_P(op1));
2547
2548    if (!ce) {
2549        if (!compile_time) {
2550            /* If we're in compile time, in practice, it's quite possible
2551             * that we'll never reach this class declaration at runtime,
2552             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
2553             * approach to work.
2554             */
2555            zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
2556        }
2557        return NULL;
2558    }
2559
2560    if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
2561        zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name->val, parent_ce->name->val);
2562    } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2563        zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name->val, parent_ce->name->val);
2564    }
2565
2566    zend_do_inheritance(ce, parent_ce TSRMLS_CC);
2567
2568    ce->refcount++;
2569
2570    /* Register the derived class */
2571    if (zend_hash_add_ptr(class_table, Z_STR_P(op2), ce) == NULL) {
2572        zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name->val);
2573    }
2574    return ce;
2575}
2576/* }}} */
2577
2578void zend_do_early_binding(TSRMLS_D) /* {{{ */
2579{
2580    zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
2581    HashTable *table;
2582
2583    while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
2584        opline--;
2585    }
2586
2587    switch (opline->opcode) {
2588        case ZEND_DECLARE_FUNCTION:
2589            if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1 TSRMLS_CC) == FAILURE) {
2590                return;
2591            }
2592            table = CG(function_table);
2593            break;
2594        case ZEND_DECLARE_CLASS:
2595            if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
2596                return;
2597            }
2598            table = CG(class_table);
2599            break;
2600        case ZEND_DECLARE_INHERITED_CLASS:
2601            {
2602                zend_op *fetch_class_opline = opline-1;
2603                zval *parent_name;
2604                zend_class_entry *ce;
2605
2606                parent_name = &CONSTANT(fetch_class_opline->op2.constant);
2607                if (((ce = zend_lookup_class(Z_STR_P(parent_name) TSRMLS_CC)) == NULL) ||
2608                    ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
2609                     (ce->type == ZEND_INTERNAL_CLASS))) {
2610                    if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) {
2611                        uint32_t *opline_num = &CG(active_op_array)->early_binding;
2612
2613                        while (*opline_num != -1) {
2614                            opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num;
2615                        }
2616                        *opline_num = opline - CG(active_op_array)->opcodes;
2617                        opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
2618                        opline->result_type = IS_UNUSED;
2619                        opline->result.opline_num = -1;
2620                    }
2621                    return;
2622                }
2623                if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), ce, 1 TSRMLS_CC) == NULL) {
2624                    return;
2625                }
2626                /* clear unnecessary ZEND_FETCH_CLASS opcode */
2627                zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
2628                MAKE_NOP(fetch_class_opline);
2629
2630                table = CG(class_table);
2631                break;
2632            }
2633        case ZEND_VERIFY_ABSTRACT_CLASS:
2634        case ZEND_ADD_INTERFACE:
2635        case ZEND_ADD_TRAIT:
2636        case ZEND_BIND_TRAITS:
2637            /* We currently don't early-bind classes that implement interfaces */
2638            /* Classes with traits are handled exactly the same, no early-bind here */
2639            return;
2640        default:
2641            zend_error_noreturn(E_COMPILE_ERROR, "Invalid binding type");
2642            return;
2643    }
2644
2645    zend_hash_del(table, Z_STR(CONSTANT(opline->op1.constant)));
2646    zend_del_literal(CG(active_op_array), opline->op1.constant);
2647    zend_del_literal(CG(active_op_array), opline->op2.constant);
2648    MAKE_NOP(opline);
2649}
2650/* }}} */
2651
2652ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */
2653{
2654    if (op_array->early_binding != -1) {
2655        zend_bool orig_in_compilation = CG(in_compilation);
2656        uint32_t opline_num = op_array->early_binding;
2657        zend_class_entry *ce;
2658
2659        CG(in_compilation) = 1;
2660        while (opline_num != -1) {
2661            if ((ce = zend_lookup_class(Z_STR_P(op_array->opcodes[opline_num-1].op2.zv) TSRMLS_CC)) != NULL) {
2662                do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), ce, 0 TSRMLS_CC);
2663            }
2664            opline_num = op_array->opcodes[opline_num].result.opline_num;
2665        }
2666        CG(in_compilation) = orig_in_compilation;
2667    }
2668}
2669/* }}} */
2670
2671ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, int internal) /* {{{ */
2672{
2673    size_t prop_name_length = 1 + src1_length + 1 + src2_length;
2674    zend_string *prop_name = zend_string_alloc(prop_name_length, internal);
2675
2676    prop_name->val[0] = '\0';
2677    memcpy(prop_name->val + 1, src1, src1_length+1);
2678    memcpy(prop_name->val + 1 + src1_length + 1, src2, src2_length+1);
2679    return prop_name;
2680}
2681/* }}} */
2682
2683static int zend_strnlen(const char* s, size_t maxlen) /* {{{ */
2684{
2685    size_t len = 0;
2686    while (*s++ && maxlen--) len++;
2687    return len;
2688}
2689/* }}} */
2690
2691ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */
2692{
2693    size_t class_name_len;
2694
2695    *class_name = NULL;
2696
2697    if (name->val[0] != '\0') {
2698        *prop_name = name->val;
2699        if (prop_len) {
2700            *prop_len = name->len;
2701        }
2702        return SUCCESS;
2703    }
2704    if (name->len < 3 || name->val[1] == '\0') {
2705        zend_error(E_NOTICE, "Illegal member variable name");
2706        *prop_name = name->val;
2707        if (prop_len) {
2708            *prop_len = name->len;
2709        }
2710        return FAILURE;
2711    }
2712
2713    class_name_len = zend_strnlen(name->val + 1, name->len - 2);
2714    if (class_name_len >= name->len - 2 || name->val[class_name_len + 1] != '\0') {
2715        zend_error(E_NOTICE, "Corrupt member variable name");
2716        *prop_name = name->val;
2717        if (prop_len) {
2718            *prop_len = name->len;
2719        }
2720        return FAILURE;
2721    }
2722
2723    *class_name = name->val + 1;
2724    *prop_name = name->val + class_name_len + 2;
2725    if (prop_len) {
2726        *prop_len = name->len - class_name_len - 2;
2727    }
2728    return SUCCESS;
2729}
2730/* }}} */
2731
2732static zend_constant *zend_get_ct_const(zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
2733{
2734    zend_constant *c = NULL;
2735    char *lookup_name;
2736
2737    if (name->val[0] == '\\') {
2738        c = zend_hash_str_find_ptr(EG(zend_constants), name->val + 1, name->len - 1);
2739        if (!c) {
2740            lookup_name = zend_str_tolower_dup(name->val + 1, name->len - 1);
2741            c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len - 1);
2742            efree(lookup_name);
2743
2744            if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
2745                return c;
2746            }
2747            return NULL;
2748        }
2749    } else if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
2750        lookup_name = zend_str_tolower_dup(name->val, name->len);
2751        c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len);
2752        efree(lookup_name);
2753
2754        if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
2755            return c;
2756        }
2757        return NULL;
2758    }
2759
2760    if (c->flags & CONST_CT_SUBST) {
2761        return c;
2762    }
2763    if (all_internal_constants_substitution &&
2764        (c->flags & CONST_PERSISTENT) &&
2765        !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) &&
2766        !Z_CONSTANT(c->value)) {
2767        return c;
2768    }
2769    return NULL;
2770}
2771/* }}} */
2772
2773static int zend_constant_ct_subst(znode *result, zval *const_name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
2774{
2775    zend_constant *c = zend_get_ct_const(Z_STR_P(const_name),
2776        all_internal_constants_substitution TSRMLS_CC);
2777
2778    if (c) {
2779        result->op_type = IS_CONST;
2780        ZVAL_DUP(&result->u.constant, &c->value);
2781        return 1;
2782    }
2783    return 0;
2784}
2785/* }}} */
2786
2787void zend_init_list(void *result, void *item TSRMLS_DC) /* {{{ */
2788{
2789    void** list = emalloc(sizeof(void*) * 2);
2790
2791    list[0] = item;
2792    list[1] = NULL;
2793
2794    *(void**)result = list;
2795}
2796/* }}} */
2797
2798void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
2799{
2800    void** list = *(void**)result;
2801    size_t n = 0;
2802
2803    if (list) {
2804        while (list[n]) {
2805            n++;
2806        }
2807    }
2808
2809    list = erealloc(list, sizeof(void*) * (n+2));
2810
2811    list[n]   = item;
2812    list[n+1] = NULL;
2813
2814    *(void**)result = list;
2815}
2816/* }}} */
2817
2818void zend_do_extended_info(TSRMLS_D) /* {{{ */
2819{
2820    zend_op *opline;
2821
2822    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2823        return;
2824    }
2825
2826    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2827
2828    opline->opcode = ZEND_EXT_STMT;
2829    SET_UNUSED(opline->op1);
2830    SET_UNUSED(opline->op2);
2831}
2832/* }}} */
2833
2834void zend_do_extended_fcall_begin(TSRMLS_D) /* {{{ */
2835{
2836    zend_op *opline;
2837
2838    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2839        return;
2840    }
2841
2842    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2843
2844    opline->opcode = ZEND_EXT_FCALL_BEGIN;
2845    SET_UNUSED(opline->op1);
2846    SET_UNUSED(opline->op2);
2847}
2848/* }}} */
2849
2850void zend_do_extended_fcall_end(TSRMLS_D) /* {{{ */
2851{
2852    zend_op *opline;
2853
2854    if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
2855        return;
2856    }
2857
2858    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2859
2860    opline->opcode = ZEND_EXT_FCALL_END;
2861    SET_UNUSED(opline->op1);
2862    SET_UNUSED(opline->op2);
2863}
2864/* }}} */
2865
2866zend_bool zend_is_auto_global(zend_string *name TSRMLS_DC) /* {{{ */
2867{
2868    zend_auto_global *auto_global;
2869
2870    if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
2871        if (auto_global->armed) {
2872            auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC);
2873        }
2874        return 1;
2875    }
2876    return 0;
2877}
2878/* }}} */
2879
2880int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global_callback auto_global_callback TSRMLS_DC) /* {{{ */
2881{
2882    zend_auto_global auto_global;
2883    int retval;
2884
2885    auto_global.name = zend_new_interned_string(name TSRMLS_CC);
2886    auto_global.auto_global_callback = auto_global_callback;
2887    auto_global.jit = jit;
2888
2889    retval = zend_hash_add_mem(CG(auto_globals), name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE;
2890
2891    zend_string_release(auto_global.name);
2892    return retval;
2893}
2894/* }}} */
2895
2896ZEND_API void zend_activate_auto_globals(TSRMLS_D) /* {{{ */
2897{
2898    zend_auto_global *auto_global;
2899
2900    ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) {
2901        if (auto_global->jit) {
2902            auto_global->armed = 1;
2903        } else if (auto_global->auto_global_callback) {
2904            auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC);
2905        } else {
2906            auto_global->armed = 0;
2907        }
2908    } ZEND_HASH_FOREACH_END();
2909}
2910/* }}} */
2911
2912int zendlex(zend_parser_stack_elem *elem TSRMLS_DC) /* {{{ */
2913{
2914    zval zv;
2915    int retval;
2916
2917    if (CG(increment_lineno)) {
2918        CG(zend_lineno)++;
2919        CG(increment_lineno) = 0;
2920    }
2921
2922again:
2923    ZVAL_UNDEF(&zv);
2924    retval = lex_scan(&zv TSRMLS_CC);
2925    switch (retval) {
2926        case T_COMMENT:
2927        case T_DOC_COMMENT:
2928        case T_OPEN_TAG:
2929        case T_WHITESPACE:
2930            goto again;
2931
2932        case T_CLOSE_TAG:
2933            if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') {
2934                CG(increment_lineno) = 1;
2935            }
2936            if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
2937                goto again;
2938            }
2939            retval = ';'; /* implicit ; */
2940            break;
2941        case T_OPEN_TAG_WITH_ECHO:
2942            retval = T_ECHO;
2943            break;
2944    }
2945    if (Z_TYPE(zv) != IS_UNDEF) {
2946        elem->ast = zend_ast_create_zval(&zv);
2947    }
2948
2949    return retval;
2950}
2951/* }}} */
2952
2953ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC) /* {{{ */
2954{
2955    zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
2956    dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR);
2957
2958    ce->refcount = 1;
2959    ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED;
2960
2961    ce->default_properties_table = NULL;
2962    ce->default_static_members_table = NULL;
2963    zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0);
2964    zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
2965    zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
2966
2967    if (ce->type == ZEND_INTERNAL_CLASS) {
2968#ifdef ZTS
2969        int n = zend_hash_num_elements(CG(class_table));
2970
2971        if (CG(static_members_table) && n >= CG(last_static_member)) {
2972            /* Support for run-time declaration: dl() */
2973            CG(last_static_member) = n+1;
2974            CG(static_members_table) = realloc(CG(static_members_table), (n+1)*sizeof(zval*));
2975            CG(static_members_table)[n] = NULL;
2976        }
2977        ce->static_members_table = (zval*)(zend_intptr_t)n;
2978#else
2979        ce->static_members_table = NULL;
2980#endif
2981    } else {
2982        ce->static_members_table = ce->default_static_members_table;
2983        ce->info.user.doc_comment = NULL;
2984    }
2985
2986    ce->default_properties_count = 0;
2987    ce->default_static_members_count = 0;
2988
2989    if (nullify_handlers) {
2990        ce->constructor = NULL;
2991        ce->destructor = NULL;
2992        ce->clone = NULL;
2993        ce->__get = NULL;
2994        ce->__set = NULL;
2995        ce->__unset = NULL;
2996        ce->__isset = NULL;
2997        ce->__call = NULL;
2998        ce->__callstatic = NULL;
2999        ce->__tostring = NULL;
3000        ce->create_object = NULL;
3001        ce->get_iterator = NULL;
3002        ce->iterator_funcs.funcs = NULL;
3003        ce->interface_gets_implemented = NULL;
3004        ce->get_static_method = NULL;
3005        ce->parent = NULL;
3006        ce->num_interfaces = 0;
3007        ce->interfaces = NULL;
3008        ce->num_traits = 0;
3009        ce->traits = NULL;
3010        ce->trait_aliases = NULL;
3011        ce->trait_precedences = NULL;
3012        ce->serialize = NULL;
3013        ce->unserialize = NULL;
3014        ce->serialize_func = NULL;
3015        ce->unserialize_func = NULL;
3016        ce->__debugInfo = NULL;
3017        if (ce->type == ZEND_INTERNAL_CLASS) {
3018            ce->info.internal.module = NULL;
3019            ce->info.internal.builtin_functions = NULL;
3020        }
3021    }
3022}
3023/* }}} */
3024
3025uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
3026{
3027    if (zend_string_equals_literal_ci(name, "self")) {
3028        return ZEND_FETCH_CLASS_SELF;
3029    } else if (zend_string_equals_literal_ci(name, "parent")) {
3030        return ZEND_FETCH_CLASS_PARENT;
3031    } else if (zend_string_equals_literal_ci(name, "static")) {
3032        return ZEND_FETCH_CLASS_STATIC;
3033    } else {
3034        return ZEND_FETCH_CLASS_DEFAULT;
3035    }
3036}
3037/* }}} */
3038
3039ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
3040{
3041    return op_array->vars[EX_VAR_TO_NUM(var)];
3042}
3043/* }}} */
3044
3045zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
3046{
3047    zval *left_zv = zend_ast_get_zval(left_ast);
3048    zend_string *left = Z_STR_P(left_zv);
3049    zend_string *right = zend_ast_get_str(right_ast);
3050
3051    zend_string *result;
3052    size_t left_len = left->len;
3053    size_t len = left_len + right->len + 1; /* left\right */
3054
3055    result = zend_string_realloc(left, len, 0);
3056    result->val[left_len] = '\\';
3057    memcpy(&result->val[left_len + 1], right->val, right->len);
3058    result->val[len] = '\0';
3059    zend_string_release(right);
3060
3061    ZVAL_STR(left_zv, result);
3062    return left_ast;
3063}
3064/* }}} */
3065
3066/* A hacky way that is used to store the doc comment for properties */
3067zend_ast *zend_ast_append_doc_comment(zend_ast *list TSRMLS_DC) /* {{{ */
3068{
3069    if (CG(doc_comment)) {
3070        list = zend_ast_list_add(list, zend_ast_create_zval_from_str(CG(doc_comment)));
3071        CG(doc_comment) = NULL;
3072    }
3073
3074    return list;
3075}
3076/* }}} */
3077
3078void zend_verify_namespace(TSRMLS_D) /* {{{ */
3079{
3080    if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
3081        zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}");
3082    }
3083}
3084/* }}} */
3085
3086static void zend_reset_import_tables(TSRMLS_D) /* {{{ */
3087{
3088    if (CG(current_import)) {
3089        zend_hash_destroy(CG(current_import));
3090        efree(CG(current_import));
3091        CG(current_import) = NULL;
3092    }
3093
3094    if (CG(current_import_function)) {
3095        zend_hash_destroy(CG(current_import_function));
3096        efree(CG(current_import_function));
3097        CG(current_import_function) = NULL;
3098    }
3099
3100    if (CG(current_import_const)) {
3101        zend_hash_destroy(CG(current_import_const));
3102        efree(CG(current_import_const));
3103        CG(current_import_const) = NULL;
3104    }
3105}
3106/* }}} */
3107
3108static void zend_end_namespace(TSRMLS_D) /* {{{ */ {
3109    CG(in_namespace) = 0;
3110    zend_reset_import_tables(TSRMLS_C);
3111    if (CG(current_namespace)) {
3112        zend_string_release(CG(current_namespace));
3113        CG(current_namespace) = NULL;
3114    }
3115}
3116/* }}} */
3117
3118void zend_do_end_compilation(TSRMLS_D) /* {{{ */
3119{
3120    CG(has_bracketed_namespaces) = 0;
3121    zend_end_namespace(TSRMLS_C);
3122}
3123/* }}} */
3124
3125/* {{{ zend_dirname
3126   Returns directory name component of path */
3127ZEND_API size_t zend_dirname(char *path, size_t len)
3128{
3129    register char *end = path + len - 1;
3130    unsigned int len_adjust = 0;
3131
3132#ifdef PHP_WIN32
3133    /* Note that on Win32 CWD is per drive (heritage from CP/M).
3134     * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
3135     */
3136    if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
3137        /* Skip over the drive spec (if any) so as not to change */
3138        path += 2;
3139        len_adjust += 2;
3140        if (2 == len) {
3141            /* Return "c:" on Win32 for dirname("c:").
3142             * It would be more consistent to return "c:."
3143             * but that would require making the string *longer*.
3144             */
3145            return len;
3146        }
3147    }
3148#elif defined(NETWARE)
3149    /*
3150     * Find the first occurrence of : from the left
3151     * move the path pointer to the position just after :
3152     * increment the len_adjust to the length of path till colon character(inclusive)
3153     * If there is no character beyond : simple return len
3154     */
3155    char *colonpos = NULL;
3156    colonpos = strchr(path, ':');
3157    if (colonpos != NULL) {
3158        len_adjust = ((colonpos - path) + 1);
3159        path += len_adjust;
3160        if (len_adjust == len) {
3161            return len;
3162        }
3163    }
3164#endif
3165
3166    if (len == 0) {
3167        /* Illegal use of this function */
3168        return 0;
3169    }
3170
3171    /* Strip trailing slashes */
3172    while (end >= path && IS_SLASH_P(end)) {
3173        end--;
3174    }
3175    if (end < path) {
3176        /* The path only contained slashes */
3177        path[0] = DEFAULT_SLASH;
3178        path[1] = '\0';
3179        return 1 + len_adjust;
3180    }
3181
3182    /* Strip filename */
3183    while (end >= path && !IS_SLASH_P(end)) {
3184        end--;
3185    }
3186    if (end < path) {
3187        /* No slash found, therefore return '.' */
3188#ifdef NETWARE
3189        if (len_adjust == 0) {
3190            path[0] = '.';
3191            path[1] = '\0';
3192            return 1; /* only one character */
3193        } else {
3194            path[0] = '\0';
3195            return len_adjust;
3196        }
3197#else
3198        path[0] = '.';
3199        path[1] = '\0';
3200        return 1 + len_adjust;
3201#endif
3202    }
3203
3204    /* Strip slashes which came before the file name */
3205    while (end >= path && IS_SLASH_P(end)) {
3206        end--;
3207    }
3208    if (end < path) {
3209        path[0] = DEFAULT_SLASH;
3210        path[1] = '\0';
3211        return 1 + len_adjust;
3212    }
3213    *(end+1) = '\0';
3214
3215    return (size_t)(end + 1 - path) + len_adjust;
3216}
3217/* }}} */
3218
3219static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */
3220{
3221    return str1->len == str2->len
3222        && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len);
3223}
3224/* }}} */
3225
3226static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
3227{
3228    switch (type & BP_VAR_MASK) {
3229        case BP_VAR_R:
3230            return;
3231        case BP_VAR_W:
3232            opline->opcode += 3;
3233            return;
3234        case BP_VAR_REF:
3235            opline->opcode += 3;
3236            opline->extended_value |= ZEND_FETCH_MAKE_REF;
3237            return;
3238        case BP_VAR_RW:
3239            opline->opcode += 6;
3240            return;
3241        case BP_VAR_IS:
3242            opline->opcode += 9;
3243            return;
3244        case BP_VAR_FUNC_ARG:
3245            opline->opcode += 12;
3246            opline->extended_value |= type >> BP_VAR_SHIFT;
3247            return;
3248        case BP_VAR_UNSET:
3249            opline->opcode += 15;
3250            return;
3251        EMPTY_SWITCH_DEFAULT_CASE()
3252    }
3253}
3254/* }}} */
3255
3256static inline void zend_make_var_result(znode *result, zend_op *opline TSRMLS_DC) /* {{{ */
3257{
3258    opline->result_type = IS_VAR;
3259    opline->result.var = get_temporary_variable(CG(active_op_array));
3260    GET_NODE(result, opline->result);
3261}
3262/* }}} */
3263
3264static inline void zend_make_tmp_result(znode *result, zend_op *opline TSRMLS_DC) /* {{{ */
3265{
3266    opline->result_type = IS_TMP_VAR;
3267    opline->result.var = get_temporary_variable(CG(active_op_array));
3268    GET_NODE(result, opline->result);
3269}
3270/* }}} */
3271
3272static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3273{
3274    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3275    opline->opcode = opcode;
3276
3277    if (op1 == NULL) {
3278        SET_UNUSED(opline->op1);
3279    } else {
3280        SET_NODE(opline->op1, op1);
3281    }
3282
3283    if (op2 == NULL) {
3284        SET_UNUSED(opline->op2);
3285    } else {
3286        SET_NODE(opline->op2, op2);
3287    }
3288
3289    if (result) {
3290        zend_make_var_result(result, opline TSRMLS_CC);
3291    }
3292    return opline;
3293}
3294/* }}} */
3295
3296static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3297{
3298    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3299    opline->opcode = opcode;
3300
3301    if (op1 == NULL) {
3302        SET_UNUSED(opline->op1);
3303    } else {
3304        SET_NODE(opline->op1, op1);
3305    }
3306
3307    if (op2 == NULL) {
3308        SET_UNUSED(opline->op2);
3309    } else {
3310        SET_NODE(opline->op2, op2);
3311    }
3312
3313    zend_make_tmp_result(result, opline TSRMLS_CC);
3314
3315    return opline;
3316}
3317/* }}} */
3318
3319static void zend_emit_tick(TSRMLS_D) /* {{{ */
3320{
3321    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3322
3323    opline->opcode = ZEND_TICKS;
3324    SET_UNUSED(opline->op1);
3325    SET_UNUSED(opline->op2);
3326    opline->extended_value = Z_LVAL(CG(declarables).ticks);
3327}
3328/* }}} */
3329
3330static inline zend_op *zend_emit_op_data(znode *value TSRMLS_DC) /* {{{ */
3331{
3332    return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL TSRMLS_CC);
3333}
3334/* }}} */
3335
3336static inline uint32_t zend_emit_jump(uint32_t opnum_target TSRMLS_DC) /* {{{ */
3337{
3338    uint32_t opnum = get_next_op_number(CG(active_op_array));
3339    zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC);
3340    opline->op1.opline_num = opnum_target;
3341    return opnum;
3342}
3343/* }}} */
3344
3345static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target TSRMLS_DC) /* {{{ */
3346{
3347    uint32_t opnum = get_next_op_number(CG(active_op_array));
3348    zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL TSRMLS_CC);
3349    opline->op2.opline_num = opnum_target;
3350    return opnum;
3351}
3352/* }}} */
3353
3354static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_target TSRMLS_DC) /* {{{ */
3355{
3356    zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
3357    switch (opline->opcode) {
3358        case ZEND_JMP:
3359            opline->op1.opline_num = opnum_target;
3360            break;
3361        case ZEND_JMPZ:
3362        case ZEND_JMPNZ:
3363        case ZEND_JMPZ_EX:
3364        case ZEND_JMPNZ_EX:
3365            opline->op2.opline_num = opnum_target;
3366            break;
3367        EMPTY_SWITCH_DEFAULT_CASE()
3368    }
3369}
3370/* }}} */
3371
3372static inline void zend_update_jump_target_to_next(uint32_t opnum_jump TSRMLS_DC) /* {{{ */
3373{
3374    zend_update_jump_target(opnum_jump, get_next_op_number(CG(active_op_array)) TSRMLS_CC);
3375}
3376/* }}} */
3377
3378static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
3379{
3380    zend_op tmp_opline;
3381    init_op(&tmp_opline TSRMLS_CC);
3382    tmp_opline.opcode = opcode;
3383    SET_NODE(tmp_opline.op1, op1);
3384    SET_NODE(tmp_opline.op2, op2);
3385    if (result) {
3386        zend_make_var_result(result, &tmp_opline TSRMLS_CC);
3387    }
3388
3389    zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline);
3390    return zend_stack_top(&CG(delayed_oplines_stack));
3391}
3392/* }}} */
3393
3394static inline uint32_t zend_delayed_compile_begin(TSRMLS_D) /* {{{ */
3395{
3396    return zend_stack_count(&CG(delayed_oplines_stack));
3397}
3398/* }}} */
3399
3400static zend_op *zend_delayed_compile_end(uint32_t offset TSRMLS_DC) /* {{{ */
3401{
3402    zend_op *opline, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
3403    uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack));
3404
3405    ZEND_ASSERT(count > offset);
3406    for (i = offset; i < count; ++i) {
3407        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3408        memcpy(opline, &oplines[i], sizeof(zend_op));
3409    }
3410    CG(delayed_oplines_stack).top = offset;
3411    return opline;
3412}
3413/* }}} */
3414
3415void zend_emit_final_return(zval *zv TSRMLS_DC) /* {{{ */
3416{
3417    znode zn;
3418    zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
3419
3420    zn.op_type = IS_CONST;
3421    if (zv) {
3422        ZVAL_COPY_VALUE(&zn.u.constant, zv);
3423    } else {
3424        ZVAL_NULL(&zn.u.constant);
3425    }
3426
3427    zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL TSRMLS_CC);
3428}
3429/* }}} */
3430
3431static inline zend_bool zend_is_variable(zend_ast *ast) /* {{{ */
3432{
3433    return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM
3434        || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP
3435        || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL
3436        || ast->kind == ZEND_AST_STATIC_CALL;
3437}
3438/* }}} */
3439
3440static inline zend_bool zend_is_call(zend_ast *ast) /* {{{ */
3441{
3442    return ast->kind == ZEND_AST_CALL
3443        || ast->kind == ZEND_AST_METHOD_CALL
3444        || ast->kind == ZEND_AST_STATIC_CALL;
3445}
3446/* }}} */
3447
3448static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
3449{
3450    return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL;
3451}
3452/* }}} */
3453
3454static inline zend_bool zend_can_write_to_variable(zend_ast *ast) /* {{{ */
3455{
3456    while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) {
3457        ast = ast->child[0];
3458    }
3459
3460    return zend_is_variable(ast);
3461}
3462/* }}} */
3463
3464static inline zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) /* {{{ */
3465{
3466    zend_string *name;
3467
3468    if (name_ast->kind != ZEND_AST_ZVAL) {
3469        return 0;
3470    }
3471
3472    /* Fully qualified names are always default refs */
3473    if (!name_ast->attr) {
3474        return 1;
3475    }
3476
3477    name = zend_ast_get_str(name_ast);
3478    return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(name);
3479}
3480/* }}} */
3481
3482static inline void zend_handle_numeric_op(znode *node TSRMLS_DC) /* {{{ */
3483{
3484    if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) {
3485        zend_ulong index;
3486
3487        if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) {
3488            zval_ptr_dtor(&node->u.constant);
3489            ZVAL_LONG(&node->u.constant, index);
3490        }
3491    }
3492}
3493/* }}} */
3494
3495static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node TSRMLS_DC) /* {{{ */
3496{
3497    if (class_node->op_type == IS_CONST) {
3498        opline->op1_type = IS_CONST;
3499        opline->op1.constant = zend_add_class_name_literal(
3500            CG(active_op_array), Z_STR(class_node->u.constant) TSRMLS_CC);
3501    } else {
3502        SET_NODE(opline->op1, class_node);
3503    }
3504}
3505/* }}} */
3506
3507static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast TSRMLS_DC) /* {{{ */
3508{
3509    zend_op *opline;
3510    znode name_node;
3511    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
3512
3513    if (name_node.op_type == IS_CONST) {
3514        zend_string *name = Z_STR(name_node.u.constant);
3515        uint32_t fetch_type = zend_get_class_fetch_type(name);
3516
3517        opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, NULL TSRMLS_CC);
3518        opline->extended_value = fetch_type;
3519
3520        if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
3521            uint32_t type = name_ast->kind == ZEND_AST_ZVAL ? name_ast->attr : ZEND_NAME_FQ;
3522            opline->op2_type = IS_CONST;
3523            opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
3524                zend_resolve_class_name(name, type TSRMLS_CC) TSRMLS_CC);
3525        }
3526
3527        zend_string_release(name);
3528    } else {
3529        opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node TSRMLS_CC);
3530        opline->extended_value = ZEND_FETCH_CLASS_DEFAULT;
3531    }
3532
3533    return opline;
3534}
3535/* }}} */
3536
3537static int zend_try_compile_cv(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3538{
3539    zend_ast *name_ast = ast->child[0];
3540    if (name_ast->kind == ZEND_AST_ZVAL) {
3541        zend_string *name = zval_get_string(zend_ast_get_zval(name_ast));
3542
3543        if (zend_is_auto_global(name TSRMLS_CC)) {
3544            zend_string_release(name);
3545            return FAILURE;
3546        }
3547
3548        result->op_type = IS_CV;
3549        result->u.op.var = lookup_cv(CG(active_op_array), name TSRMLS_CC);
3550
3551        if (zend_string_equals_literal(name, "this")) {
3552            CG(active_op_array)->this_var = result->u.op.var;
3553        }
3554        return SUCCESS;
3555    }
3556
3557    return FAILURE;
3558}
3559/* }}} */
3560
3561static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3562{
3563    zend_ast *name_ast = ast->child[0];
3564    znode name_node;
3565    zend_op *opline;
3566
3567    /* there is a chance someone is accessing $this */
3568    if (ast->kind != ZEND_AST_ZVAL
3569        && CG(active_op_array)->scope && CG(active_op_array)->this_var == -1
3570    ) {
3571        zend_string *key = zend_string_init("this", sizeof("this") - 1, 0);
3572        CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), key TSRMLS_CC);
3573    }
3574
3575    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
3576
3577    opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL TSRMLS_CC);
3578
3579    opline->extended_value = ZEND_FETCH_LOCAL;
3580    if (name_node.op_type == IS_CONST) {
3581        if (zend_is_auto_global(Z_STR(name_node.u.constant) TSRMLS_CC)) {
3582            opline->extended_value = ZEND_FETCH_GLOBAL;
3583        }
3584    }
3585
3586    return opline;
3587}
3588/* }}} */
3589
3590static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3591{
3592    if (zend_try_compile_cv(result, ast TSRMLS_CC) == FAILURE) {
3593        zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type TSRMLS_CC);
3594        zend_adjust_for_fetch_type(opline, type);
3595    }
3596}
3597/* }}} */
3598
3599static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3600{
3601    if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
3602        if (node->op_type == IS_VAR) {
3603            zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL TSRMLS_CC);
3604            opline->result_type = IS_VAR;
3605            opline->result.var = opline->op1.var;
3606        } else {
3607            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
3608        }
3609    }
3610}
3611/* }}} */
3612
3613void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC);
3614
3615static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3616{
3617    zend_ast *var_ast = ast->child[0];
3618    zend_ast *dim_ast = ast->child[1];
3619
3620    znode var_node, dim_node;
3621
3622    zend_delayed_compile_var(&var_node, var_ast, type TSRMLS_CC);
3623    zend_separate_if_call_and_write(&var_node, var_ast, type TSRMLS_CC);
3624
3625    if (dim_ast == NULL) {
3626        if (type == BP_VAR_R || type == BP_VAR_IS) {
3627            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
3628        }
3629        if (type == BP_VAR_UNSET) {
3630            zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
3631        }
3632        dim_node.op_type = IS_UNUSED;
3633    } else {
3634        zend_compile_expr(&dim_node, dim_ast TSRMLS_CC);
3635        zend_handle_numeric_op(&dim_node TSRMLS_CC);
3636    }
3637
3638    return zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node TSRMLS_CC);
3639}
3640/* }}} */
3641
3642static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3643{
3644    uint32_t offset = zend_delayed_compile_begin(TSRMLS_C);
3645    zend_delayed_compile_dim(result, ast, type TSRMLS_CC);
3646    return zend_delayed_compile_end(offset TSRMLS_CC);
3647}
3648/* }}} */
3649
3650void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3651{
3652    zend_op *opline = zend_compile_dim_common(result, ast, type TSRMLS_CC);
3653    zend_adjust_for_fetch_type(opline, type);
3654}
3655/* }}} */
3656
3657static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
3658{
3659    if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
3660        zval *name = zend_ast_get_zval(ast->child[0]);
3661        return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
3662    }
3663
3664    return 0;
3665}
3666/* }}} */
3667
3668static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3669{
3670    zend_ast *obj_ast = ast->child[0];
3671    zend_ast *prop_ast = ast->child[1];
3672
3673    znode obj_node, prop_node;
3674    zend_op *opline;
3675
3676    if (is_this_fetch(obj_ast)) {
3677        obj_node.op_type = IS_UNUSED;
3678    } else {
3679        zend_delayed_compile_var(&obj_node, obj_ast, type TSRMLS_CC);
3680        zend_separate_if_call_and_write(&obj_node, obj_ast, type TSRMLS_CC);
3681    }
3682    zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
3683
3684    opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node TSRMLS_CC);
3685    if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
3686        zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
3687    }
3688
3689    return opline;
3690}
3691/* }}} */
3692
3693static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3694{
3695    uint32_t offset = zend_delayed_compile_begin(TSRMLS_C);
3696    zend_delayed_compile_prop(result, ast, type TSRMLS_CC);
3697    return zend_delayed_compile_end(offset TSRMLS_CC);
3698}
3699/* }}} */
3700
3701void zend_compile_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3702{
3703    zend_op *opline = zend_compile_prop_common(result, ast, type TSRMLS_CC);
3704    zend_adjust_for_fetch_type(opline, type);
3705}
3706/* }}} */
3707
3708zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3709{
3710    zend_ast *class_ast = ast->child[0];
3711    zend_ast *prop_ast = ast->child[1];
3712
3713    znode class_node, prop_node;
3714    zend_op *opline;
3715
3716    if (zend_is_const_default_class_ref(class_ast)) {
3717        class_node.op_type = IS_CONST;
3718        ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC));
3719    } else {
3720        zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
3721    }
3722
3723    zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
3724
3725    opline = zend_emit_op(result, ZEND_FETCH_R, &prop_node, NULL TSRMLS_CC);
3726    if (opline->op1_type == IS_CONST) {
3727        zend_alloc_polymorphic_cache_slot(opline->op1.constant TSRMLS_CC);
3728    }
3729    if (class_node.op_type == IS_CONST) {
3730        opline->op2_type = IS_CONST;
3731        opline->op2.constant = zend_add_class_name_literal(
3732            CG(active_op_array), Z_STR(class_node.u.constant) TSRMLS_CC);
3733    } else {
3734        SET_NODE(opline->op2, &class_node);
3735    }
3736    opline->extended_value |= ZEND_FETCH_STATIC_MEMBER;
3737
3738    return opline;
3739}
3740/* }}} */
3741
3742void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
3743{
3744    zend_op *opline = zend_compile_static_prop_common(result, ast, type TSRMLS_CC);
3745    zend_adjust_for_fetch_type(opline, type);
3746}
3747/* }}} */
3748
3749static inline zend_uchar get_list_fetch_opcode(zend_uchar op_type) /* {{{ */
3750{
3751    switch (op_type) {
3752        case IS_VAR:
3753        case IS_CV:
3754            return ZEND_FETCH_DIM_R;
3755        case IS_TMP_VAR:
3756        case IS_CONST:
3757            return ZEND_FETCH_DIM_TMP_VAR;
3758        EMPTY_SWITCH_DEFAULT_CASE()
3759    }
3760}
3761/* }}} */
3762
3763static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node TSRMLS_DC) /* {{{ */
3764{
3765    zend_ast_list *list = zend_ast_get_list(ast);
3766    uint32_t i;
3767
3768    if (list->children == 1 && !list->child[0]) {
3769        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list");
3770    }
3771
3772    for (i = 0; i < list->children; ++i) {
3773        zend_ast *var_ast = list->child[i];
3774        znode fetch_result, dim_node, var_node, assign_result;
3775        zend_op *opline;
3776
3777        if (var_ast == NULL) {
3778            continue;
3779        }
3780
3781        dim_node.op_type = IS_CONST;
3782        ZVAL_LONG(&dim_node.u.constant, i);
3783
3784        if (expr_node->op_type == IS_CONST) {
3785            Z_TRY_ADDREF(expr_node->u.constant);
3786        }
3787
3788        opline = zend_emit_op(&fetch_result,
3789            get_list_fetch_opcode(expr_node->op_type), expr_node, &dim_node TSRMLS_CC);
3790        opline->extended_value |= ZEND_FETCH_ADD_LOCK;
3791
3792        if (var_ast->kind != ZEND_AST_LIST) {
3793            if (is_this_fetch(var_ast)) {
3794                zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3795            }
3796            zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC);
3797            zend_emit_op(&assign_result, ZEND_ASSIGN, &var_node, &fetch_result TSRMLS_CC);
3798            zend_do_free(&assign_result TSRMLS_CC);
3799        } else {
3800            zend_compile_list_assign(&assign_result, var_ast, &fetch_result TSRMLS_CC);
3801            zend_do_free(&assign_result TSRMLS_CC);
3802        }
3803    }
3804    *result = *expr_node;
3805}
3806/* }}} */
3807
3808void zend_ensure_writable_variable(const zend_ast *ast) /* {{{ */
3809{
3810    if (ast->kind == ZEND_AST_CALL) {
3811        zend_error_noreturn(E_COMPILE_ERROR, "Can't use function return value in write context");
3812    }
3813    if (ast->kind == ZEND_AST_METHOD_CALL || ast->kind == ZEND_AST_STATIC_CALL) {
3814        zend_error_noreturn(E_COMPILE_ERROR, "Can't use method return value in write context");
3815    }
3816}
3817/* }}} */
3818
3819/* Detects $a... = $a pattern */
3820zend_bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast TSRMLS_DC) /* {{{ */
3821{
3822    if (expr_ast->kind != ZEND_AST_VAR || expr_ast->child[0]->kind != ZEND_AST_ZVAL) {
3823        return 0;
3824    }
3825
3826    while (zend_is_variable(var_ast) && var_ast->kind != ZEND_AST_VAR) {
3827        var_ast = var_ast->child[0];
3828    }
3829
3830    if (var_ast->kind != ZEND_AST_VAR || var_ast->child[0]->kind != ZEND_AST_ZVAL) {
3831        return 0;
3832    }
3833
3834    {
3835        zend_string *name1 = zval_get_string(zend_ast_get_zval(var_ast->child[0]));
3836        zend_string *name2 = zval_get_string(zend_ast_get_zval(expr_ast->child[0]));
3837        zend_bool result = zend_string_equals(name1, name2);
3838        zend_string_release(name1);
3839        zend_string_release(name2);
3840        return result;
3841    }
3842}
3843/* }}} */
3844
3845void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3846{
3847    zend_ast *var_ast = ast->child[0];
3848    zend_ast *expr_ast = ast->child[1];
3849
3850    znode var_node, expr_node;
3851    zend_op *opline;
3852    uint32_t offset;
3853
3854    if (is_this_fetch(var_ast)) {
3855        zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3856    }
3857
3858    zend_ensure_writable_variable(var_ast);
3859
3860    switch (var_ast->kind) {
3861        case ZEND_AST_VAR:
3862        case ZEND_AST_STATIC_PROP:
3863            zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC);
3864            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3865            zend_emit_op(result, ZEND_ASSIGN, &var_node, &expr_node TSRMLS_CC);
3866            return;
3867        case ZEND_AST_DIM:
3868            offset = zend_delayed_compile_begin(TSRMLS_C);
3869            zend_delayed_compile_dim(result, var_ast, BP_VAR_W TSRMLS_CC);
3870
3871            if (zend_is_assign_to_self(var_ast, expr_ast TSRMLS_CC)) {
3872                /* $a[0] = $a should evaluate the right $a first */
3873                zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R TSRMLS_CC);
3874            } else {
3875                zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3876            }
3877
3878            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3879            opline->opcode = ZEND_ASSIGN_DIM;
3880
3881            opline = zend_emit_op_data(&expr_node TSRMLS_CC);
3882            opline->op2.var = get_temporary_variable(CG(active_op_array));
3883            opline->op2_type = IS_VAR;
3884            return;
3885        case ZEND_AST_PROP:
3886            offset = zend_delayed_compile_begin(TSRMLS_C);
3887            zend_delayed_compile_prop(result, var_ast, BP_VAR_W TSRMLS_CC);
3888            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3889
3890            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3891            opline->opcode = ZEND_ASSIGN_OBJ;
3892
3893            zend_emit_op_data(&expr_node TSRMLS_CC);
3894            return;
3895        case ZEND_AST_LIST:
3896            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3897            zend_compile_list_assign(result, var_ast, &expr_node TSRMLS_CC);
3898            return;
3899        EMPTY_SWITCH_DEFAULT_CASE();
3900    }
3901}
3902/* }}} */
3903
3904static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
3905{
3906    znode dummy_node;
3907    zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
3908        zend_ast_create_znode(value_node));
3909    zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC);
3910    zend_do_free(&dummy_node TSRMLS_CC);
3911}
3912/* }}} */
3913
3914void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3915{
3916    zend_ast *target_ast = ast->child[0];
3917    zend_ast *source_ast = ast->child[1];
3918
3919    znode target_node, source_node;
3920    zend_op *opline;
3921
3922    if (is_this_fetch(target_ast)) {
3923        zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3924    }
3925    zend_ensure_writable_variable(target_ast);
3926
3927    zend_compile_var(&target_node, target_ast, BP_VAR_W TSRMLS_CC);
3928    zend_compile_var(&source_node, source_ast, BP_VAR_REF TSRMLS_CC);
3929
3930    opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node TSRMLS_CC);
3931    if (!result) {
3932        opline->result_type |= EXT_TYPE_UNUSED;
3933    }
3934
3935    if (zend_is_call(source_ast)) {
3936        opline->extended_value = ZEND_RETURNS_FUNCTION;
3937    } else if (source_ast->kind == ZEND_AST_NEW) {
3938        zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated");
3939        opline->extended_value = ZEND_RETURNS_NEW;
3940    }
3941}
3942/* }}} */
3943
3944static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
3945{
3946    zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN_REF, var_ast,
3947        zend_ast_create_znode(value_node));
3948    zend_compile_assign_ref(NULL, assign_ast TSRMLS_CC);
3949}
3950/* }}} */
3951
3952void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
3953{
3954    zend_ast *var_ast = ast->child[0];
3955    zend_ast *expr_ast = ast->child[1];
3956    uint32_t opcode = ast->attr;
3957
3958    znode var_node, expr_node;
3959    zend_op *opline;
3960    uint32_t offset;
3961
3962    zend_ensure_writable_variable(var_ast);
3963
3964    switch (var_ast->kind) {
3965        case ZEND_AST_VAR:
3966        case ZEND_AST_STATIC_PROP:
3967            zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
3968            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3969            zend_emit_op(result, opcode, &var_node, &expr_node TSRMLS_CC);
3970            return;
3971        case ZEND_AST_DIM:
3972            offset = zend_delayed_compile_begin(TSRMLS_C);
3973            zend_delayed_compile_dim(result, var_ast, BP_VAR_RW TSRMLS_CC);
3974            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3975
3976            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3977            opline->opcode = opcode;
3978            opline->extended_value = ZEND_ASSIGN_DIM;
3979
3980            opline = zend_emit_op_data(&expr_node TSRMLS_CC);
3981            opline->op2.var = get_temporary_variable(CG(active_op_array));
3982            opline->op2_type = IS_VAR;
3983            return;
3984        case ZEND_AST_PROP:
3985            offset = zend_delayed_compile_begin(TSRMLS_C);
3986            zend_delayed_compile_prop(result, var_ast, BP_VAR_RW TSRMLS_CC);
3987            zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
3988
3989            opline = zend_delayed_compile_end(offset TSRMLS_CC);
3990            opline->opcode = opcode;
3991            opline->extended_value = ZEND_ASSIGN_OBJ;
3992
3993            zend_emit_op_data(&expr_node TSRMLS_CC);
3994            return;
3995        EMPTY_SWITCH_DEFAULT_CASE()
3996    }
3997}
3998/* }}} */
3999
4000uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc TSRMLS_DC) /* {{{ */
4001{
4002    /* TODO.AST &var error */
4003    zend_ast_list *args = zend_ast_get_list(ast);
4004    uint32_t i;
4005    zend_bool uses_arg_unpack = 0;
4006    uint32_t arg_count = 0; /* number of arguments not including unpacks */
4007
4008    for (i = 0; i < args->children; ++i) {
4009        zend_ast *arg = args->child[i];
4010        uint32_t arg_num = i + 1;
4011
4012        znode arg_node;
4013        zend_op *opline;
4014        zend_uchar opcode;
4015        zend_ulong flags = 0;
4016
4017        if (arg->kind == ZEND_AST_UNPACK) {
4018            uses_arg_unpack = 1;
4019            fbc = NULL;
4020
4021            zend_compile_expr(&arg_node, arg->child[0] TSRMLS_CC);
4022            opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL TSRMLS_CC);
4023            opline->op2.num = arg_count;
4024            continue;
4025        }
4026
4027        if (uses_arg_unpack) {
4028            zend_error_noreturn(E_COMPILE_ERROR,
4029                "Cannot use positional argument after argument unpacking");
4030        }
4031
4032        arg_count++;
4033        if (zend_is_variable(arg)) {
4034            if (zend_is_call(arg)) {
4035                zend_compile_var(&arg_node, arg, BP_VAR_R TSRMLS_CC);
4036                if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
4037                    /* Function call was converted into builtin instruction */
4038                    opcode = ZEND_SEND_VAL;
4039                } else {
4040                    opcode = ZEND_SEND_VAR_NO_REF;
4041                    flags |= ZEND_ARG_SEND_FUNCTION;
4042                    if (fbc && ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
4043                        flags |= ZEND_ARG_SEND_BY_REF;
4044                        if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
4045                            flags |= ZEND_ARG_SEND_SILENT;
4046                        }
4047                    }
4048                }
4049            } else if (fbc) {
4050                if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
4051                    zend_compile_var(&arg_node, arg, BP_VAR_W TSRMLS_CC);
4052                    opcode = ZEND_SEND_REF;
4053                } else {
4054                    zend_compile_var(&arg_node, arg, BP_VAR_R TSRMLS_CC);
4055                    opcode = ZEND_SEND_VAR;
4056                }
4057            } else {
4058                zend_compile_var(&arg_node, arg,
4059                    BP_VAR_FUNC_ARG | (arg_num << BP_VAR_SHIFT) TSRMLS_CC);
4060                opcode = ZEND_SEND_VAR_EX;
4061            }
4062        } else {
4063            zend_compile_expr(&arg_node, arg TSRMLS_CC);
4064            if (arg_node.op_type & (IS_VAR|IS_CV)) {
4065                opcode = ZEND_SEND_VAR_NO_REF;
4066                if (fbc && ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
4067                    flags |= ZEND_ARG_SEND_BY_REF;
4068                }
4069            } else {
4070                if (fbc) {
4071                    opcode = ZEND_SEND_VAL;
4072                    if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
4073                        zend_error_noreturn(E_COMPILE_ERROR, "Only variables can be passed by reference");
4074                    }
4075                } else {
4076                    opcode = ZEND_SEND_VAL_EX;
4077                }
4078            }
4079        }
4080
4081        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4082        opline->opcode = opcode;
4083        SET_NODE(opline->op1, &arg_node);
4084        SET_UNUSED(opline->op2);
4085        opline->op2.opline_num = arg_num;
4086
4087        if (opcode == ZEND_SEND_VAR_NO_REF) {
4088            if (fbc) {
4089                flags |= ZEND_ARG_COMPILE_TIME_BOUND;
4090            }
4091            opline->extended_value = flags;
4092        } else if (fbc) {
4093            opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
4094        }
4095    }
4096
4097    return arg_count;
4098}
4099/* }}} */
4100
4101void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc TSRMLS_DC) /* {{{ */
4102{
4103    zend_op *opline;
4104    uint32_t opnum_init = get_next_op_number(CG(active_op_array)) - 1;
4105    uint32_t arg_count;
4106    uint32_t call_flags;
4107
4108    zend_do_extended_fcall_begin(TSRMLS_C);
4109
4110    arg_count = zend_compile_args(args_ast, fbc TSRMLS_CC);
4111
4112    opline = &CG(active_op_array)->opcodes[opnum_init];
4113    opline->extended_value = arg_count;
4114
4115    call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0);
4116    opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4117    opline->op1.num = call_flags;
4118
4119    zend_do_extended_fcall_end(TSRMLS_C);
4120}
4121/* }}} */
4122
4123zend_bool zend_compile_function_name(znode *name_node, zend_ast *name_ast TSRMLS_DC) /* {{{ */
4124{
4125    zend_string *orig_name = zend_ast_get_str(name_ast);
4126    zend_bool is_fully_qualified;
4127
4128    name_node->op_type = IS_CONST;
4129    ZVAL_STR(&name_node->u.constant, zend_resolve_function_name(
4130        orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC));
4131
4132    return !is_fully_qualified && CG(current_namespace);
4133}
4134/* }}} */
4135
4136void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast TSRMLS_DC) /* {{{ */
4137{
4138    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4139    opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
4140    SET_UNUSED(opline->op1);
4141    opline->op2_type = IS_CONST;
4142    opline->op2.constant = zend_add_ns_func_name_literal(
4143        CG(active_op_array), &name_node->u.constant TSRMLS_CC);
4144    zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4145
4146    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4147}
4148/* }}} */
4149
4150void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast TSRMLS_DC) /* {{{ */
4151{
4152    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4153    opline->opcode = ZEND_INIT_FCALL_BY_NAME;
4154    SET_UNUSED(opline->op1);
4155    if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
4156        opline->op2_type = IS_CONST;
4157        opline->op2.constant
4158            = zend_add_func_name_literal(CG(active_op_array), &name_node->u.constant TSRMLS_CC);
4159        zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4160    } else {
4161        SET_NODE(opline->op2, name_node);
4162    }
4163
4164    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4165}
4166/* }}} */
4167
4168static zend_bool zend_args_contain_unpack(zend_ast_list *args) /* {{{ */
4169{
4170    uint32_t i;
4171    for (i = 0; i < args->children; ++i) {
4172        if (args->child[i]->kind == ZEND_AST_UNPACK) {
4173            return 1;
4174        }
4175    }
4176    return 0;
4177}
4178/* }}} */
4179
4180int zend_compile_func_strlen(znode *result, zend_ast_list *args TSRMLS_DC) /* {{{ */
4181{
4182    znode arg_node;
4183
4184    if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)
4185        || args->children != 1 || args->child[0]->kind == ZEND_AST_UNPACK
4186    ) {
4187        return FAILURE;
4188    }
4189
4190    zend_compile_expr(&arg_node, args->child[0] TSRMLS_CC);
4191    zend_emit_op_tmp(result, ZEND_STRLEN, &arg_node, NULL TSRMLS_CC);
4192    return SUCCESS;
4193}
4194/* }}} */
4195
4196int zend_compile_func_typecheck(znode *result, zend_ast_list *args, uint32_t type TSRMLS_DC) /* {{{ */
4197{
4198    znode arg_node;
4199    zend_op *opline;
4200
4201    if (args->children != 1 || args->child[0]->kind == ZEND_AST_UNPACK) {
4202        return FAILURE;
4203    }
4204
4205    zend_compile_expr(&arg_node, args->child[0] TSRMLS_CC);
4206    opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL TSRMLS_CC);
4207    opline->extended_value = type;
4208    return SUCCESS;
4209}
4210/* }}} */
4211
4212int zend_compile_func_defined(znode *result, zend_ast_list *args TSRMLS_DC) /* {{{ */
4213{
4214    zend_string *name;
4215    zend_op *opline;
4216
4217    if (args->children != 1 || args->child[0]->kind != ZEND_AST_ZVAL) {
4218        return FAILURE;
4219    }
4220
4221    name = zval_get_string(zend_ast_get_zval(args->child[0]));
4222    if (zend_memrchr(name->val, '\\', name->len) || zend_memrchr(name->val, ':', name->len)) {
4223        zend_string_release(name);
4224        return FAILURE;
4225    }
4226
4227    opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL TSRMLS_CC);
4228    opline->op1_type = IS_CONST;
4229    LITERAL_STR(opline->op1, name);
4230    zend_alloc_cache_slot(opline->op1.constant TSRMLS_CC);
4231
4232    /* Lowercase constant name in a separate literal */
4233    {
4234        zval c;
4235        zend_string *lcname = zend_string_alloc(name->len, 0);
4236        zend_str_tolower_copy(lcname->val, name->val, name->len);
4237        ZVAL_NEW_STR(&c, lcname);
4238        zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
4239    }
4240    return SUCCESS;
4241}
4242/* }}} */
4243
4244static int zend_try_compile_ct_bound_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args TSRMLS_DC) /* {{{ */
4245{
4246    zend_string *name, *lcname;
4247    zend_function *fbc;
4248    zend_op *opline;
4249
4250    if (name_ast->kind != ZEND_AST_CONST || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
4251        return FAILURE;
4252    }
4253
4254    name = zend_ast_get_str(name_ast);
4255    lcname = zend_string_alloc(name->len, 0);
4256    zend_str_tolower_copy(lcname->val, name->val, name->len);
4257
4258    fbc = zend_hash_find_ptr(CG(function_table), lcname);
4259    if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION &&
4260        (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
4261    ) {
4262        zend_string_free(lcname);
4263        return FAILURE;
4264    }
4265
4266    opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, NULL TSRMLS_CC);
4267    opline->op2_type = IS_CONST;
4268    LITERAL_STR(opline->op2, lcname);
4269    opline->extended_value = num_args;
4270
4271    return SUCCESS;
4272}
4273/* }}} */
4274
4275static void zend_compile_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name TSRMLS_DC) /* {{{ */
4276{
4277    zend_op *opline;
4278    znode name_node;
4279
4280    if (zend_try_compile_ct_bound_init_user_func(result, name_ast, num_args TSRMLS_CC) == SUCCESS) {
4281        return;
4282    }
4283
4284    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4285
4286    opline = zend_emit_op(NULL, ZEND_INIT_USER_CALL, NULL, &name_node TSRMLS_CC);
4287    opline->op1_type = IS_CONST;
4288    LITERAL_STR(opline->op1, zend_string_copy(orig_func_name));
4289    opline->extended_value = num_args;
4290}
4291/* }}} */
4292
4293/* cufa = call_user_func_array */
4294int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcname TSRMLS_DC) /* {{{ */
4295{
4296    znode arg_node;
4297
4298    if (args->children != 2 || zend_args_contain_unpack(args)) {
4299        return FAILURE;
4300    }
4301
4302    zend_compile_init_user_func(NULL, args->child[0], 1, lcname TSRMLS_CC);
4303    zend_compile_expr(&arg_node, args->child[1] TSRMLS_CC);
4304    zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL TSRMLS_CC);
4305    zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4306
4307    return SUCCESS;
4308}
4309/* }}} */
4310
4311/* cuf = call_user_func */
4312int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname TSRMLS_DC) /* {{{ */
4313{
4314    uint32_t i;
4315
4316    if (args->children < 1 || zend_args_contain_unpack(args)) {
4317        return FAILURE;
4318    }
4319
4320    zend_compile_init_user_func(NULL, args->child[0], args->children - 1, lcname TSRMLS_CC);
4321    for (i = 1; i < args->children; ++i) {
4322        zend_ast *arg_ast = args->child[i];
4323        znode arg_node;
4324        zend_op *opline;
4325        zend_bool send_user = 0;
4326
4327        if (zend_is_variable(arg_ast) && !zend_is_call(arg_ast)) {
4328            zend_compile_var(&arg_node, arg_ast, BP_VAR_FUNC_ARG | (i << BP_VAR_SHIFT) TSRMLS_CC);
4329            send_user = 1;
4330        } else {
4331            zend_compile_expr(&arg_node, arg_ast TSRMLS_CC);
4332            if (arg_node.op_type & (IS_VAR|IS_CV)) {
4333                send_user = 1;
4334            }
4335        }
4336
4337        if (send_user) {
4338            opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL TSRMLS_CC);
4339        } else {
4340            opline = zend_emit_op(NULL, ZEND_SEND_VAL, &arg_node, NULL TSRMLS_CC);
4341        }
4342
4343        opline->op2.opline_num = i;
4344    }
4345    zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
4346
4347    return SUCCESS;
4348}
4349/* }}} */
4350
4351int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args TSRMLS_DC) /* {{{ */
4352{
4353    if (zend_string_equals_literal(lcname, "strlen")) {
4354        return zend_compile_func_strlen(result, args TSRMLS_CC);
4355    } else if (zend_string_equals_literal(lcname, "is_null")) {
4356        return zend_compile_func_typecheck(result, args, IS_NULL TSRMLS_CC);
4357    } else if (zend_string_equals_literal(lcname, "is_bool")) {
4358        return zend_compile_func_typecheck(result, args, _IS_BOOL TSRMLS_CC);
4359    } else if (zend_string_equals_literal(lcname, "is_long")
4360        || zend_string_equals_literal(lcname, "is_int")
4361        || zend_string_equals_literal(lcname, "is_integer")
4362    ) {
4363        return zend_compile_func_typecheck(result, args, IS_LONG TSRMLS_CC);
4364    } else if (zend_string_equals_literal(lcname, "is_float")
4365        || zend_string_equals_literal(lcname, "is_double")
4366        || zend_string_equals_literal(lcname, "is_real")
4367    ) {
4368        return zend_compile_func_typecheck(result, args, IS_DOUBLE TSRMLS_CC);
4369    } else if (zend_string_equals_literal(lcname, "is_string")) {
4370        return zend_compile_func_typecheck(result, args, IS_STRING TSRMLS_CC);
4371    } else if (zend_string_equals_literal(lcname, "is_array")) {
4372        return zend_compile_func_typecheck(result, args, IS_ARRAY TSRMLS_CC);
4373    } else if (zend_string_equals_literal(lcname, "is_object")) {
4374        return zend_compile_func_typecheck(result, args, IS_OBJECT TSRMLS_CC);
4375    } else if (zend_string_equals_literal(lcname, "is_resource")) {
4376        return zend_compile_func_typecheck(result, args, IS_RESOURCE TSRMLS_CC);
4377    } else if (zend_string_equals_literal(lcname, "defined")) {
4378        return zend_compile_func_defined(result, args TSRMLS_CC);
4379    } else if (zend_string_equals_literal(lcname, "call_user_func_array")) {
4380        return zend_compile_func_cufa(result, args, lcname TSRMLS_CC);
4381    } else if (zend_string_equals_literal(lcname, "call_user_func")) {
4382        return zend_compile_func_cuf(result, args, lcname TSRMLS_CC);
4383    } else {
4384        return FAILURE;
4385    }
4386}
4387/* }}} */
4388
4389void zend_compile_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4390{
4391    zend_ast *name_ast = ast->child[0];
4392    zend_ast *args_ast = ast->child[1];
4393
4394    znode name_node;
4395
4396    if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
4397        zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4398        zend_compile_dynamic_call(result, &name_node, args_ast TSRMLS_CC);
4399        return;
4400    }
4401
4402    {
4403        zend_bool runtime_resolution = zend_compile_function_name(&name_node, name_ast TSRMLS_CC);
4404        if (runtime_resolution) {
4405            zend_compile_ns_call(result, &name_node, args_ast TSRMLS_CC);
4406            return;
4407        }
4408    }
4409
4410    {
4411        zval *name = &name_node.u.constant;
4412        zend_string *lcname = zend_string_alloc(Z_STRLEN_P(name), 0);
4413        zend_function *fbc;
4414        zend_op *opline;
4415
4416        zend_str_tolower_copy(lcname->val, Z_STRVAL_P(name), Z_STRLEN_P(name));
4417
4418        fbc = zend_hash_find_ptr(CG(function_table), lcname);
4419        if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION &&
4420            (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
4421        ) {
4422            zend_string_release(lcname);
4423            zend_compile_dynamic_call(result, &name_node, args_ast TSRMLS_CC);
4424            return;
4425        }
4426
4427        if (zend_try_compile_special_func(result, lcname,
4428                zend_ast_get_list(args_ast) TSRMLS_CC) == SUCCESS
4429        ) {
4430            zend_string_release(lcname);
4431            zval_ptr_dtor(&name_node.u.constant);
4432            return;
4433        }
4434
4435        zval_ptr_dtor(&name_node.u.constant);
4436        ZVAL_NEW_STR(&name_node.u.constant, lcname);
4437
4438        opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node TSRMLS_CC);
4439        zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4440
4441        zend_compile_call_common(result, args_ast, fbc TSRMLS_CC);
4442    }
4443}
4444/* }}} */
4445
4446void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4447{
4448    zend_ast *obj_ast = ast->child[0];
4449    zend_ast *method_ast = ast->child[1];
4450    zend_ast *args_ast = ast->child[2];
4451
4452    znode obj_node, method_node;
4453    zend_op *opline;
4454
4455    if (is_this_fetch(obj_ast)) {
4456        obj_node.op_type = IS_UNUSED;
4457    } else {
4458        zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
4459    }
4460
4461    zend_compile_expr(&method_node, method_ast TSRMLS_CC);
4462    opline = zend_emit_op(NULL, ZEND_INIT_METHOD_CALL, &obj_node, NULL TSRMLS_CC);
4463
4464    if (method_node.op_type == IS_CONST) {
4465        if (Z_TYPE(method_node.u.constant) != IS_STRING) {
4466            zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
4467        }
4468
4469        opline->op2_type = IS_CONST;
4470        opline->op2.constant =
4471            zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
4472        zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
4473    } else {
4474        SET_NODE(opline->op2, &method_node);
4475    }
4476
4477    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4478}
4479/* }}} */
4480
4481zend_bool zend_is_constructor(zend_string *name) /* {{{ */
4482{
4483    return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
4484}
4485/* }}} */
4486
4487void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
4488{
4489    zend_ast *class_ast = ast->child[0];
4490    zend_ast *method_ast = ast->child[1];
4491    zend_ast *args_ast = ast->child[2];
4492
4493    znode class_node, method_node;
4494    zend_op *opline;
4495    zend_ulong extended_value = 0;
4496
4497    if (zend_is_const_default_class_ref(class_ast)) {
4498        class_node.op_type = IS_CONST;
4499        ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC));
4500    } else {
4501        opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
4502        extended_value = opline->extended_value;
4503    }
4504
4505    zend_compile_expr(&method_node, method_ast TSRMLS_CC);
4506    if (method_node.op_type == IS_CONST) {
4507        zval *name = &method_node.u.constant;
4508        if (Z_TYPE_P(name) != IS_STRING) {
4509            zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
4510        }
4511        if (zend_is_constructor(Z_STR_P(name))) {
4512            zval_ptr_dtor(name);
4513            method_node.op_type = IS_UNUSED;
4514        }
4515    }
4516
4517    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4518    opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
4519    opline->extended_value = extended_value;
4520
4521    zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
4522
4523    if (method_node.op_type == IS_CONST) {
4524        opline->op2_type = IS_CONST;
4525        opline->op2.constant =
4526            zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
4527        if (opline->op1_type == IS_CONST) {
4528            zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
4529        } else {
4530            zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
4531        }
4532    } else {
4533        SET_NODE(opline->op2, &method_node);
4534    }
4535
4536    zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
4537}
4538/* }}} */
4539
4540void zend_compile_new(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
4541{
4542    zend_ast *class_ast = ast->child[0];
4543    zend_ast *args_ast = ast->child[1];
4544
4545    znode class_node, ctor_result;
4546    zend_op *opline;
4547    uint32_t opnum;
4548
4549    zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
4550
4551    opnum = get_next_op_number(CG(active_op_array));
4552    zend_emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC);
4553
4554    zend_compile_call_common(&ctor_result, args_ast, NULL TSRMLS_CC);
4555    zend_do_free(&ctor_result TSRMLS_CC);
4556
4557    /* New jumps over ctor call if ctor does not exist */
4558    opline = &CG(active_op_array)->opcodes[opnum];
4559    opline->op2.opline_num = get_next_op_number(CG(active_op_array));
4560}
4561/* }}} */
4562
4563void zend_compile_clone(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
4564{
4565    zend_ast *obj_ast = ast->child[0];
4566
4567    znode obj_node;
4568    zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
4569
4570    zend_emit_op(result, ZEND_CLONE, &obj_node, NULL TSRMLS_CC);
4571}
4572/* }}} */
4573
4574void zend_compile_global_var(zend_ast *ast TSRMLS_DC) /* {{{ */
4575{
4576    zend_ast *var_ast = ast->child[0];
4577    zend_ast *name_ast = var_ast->child[0];
4578
4579    znode name_node, result;
4580
4581    zend_compile_expr(&name_node, name_ast TSRMLS_CC);
4582    if (name_node.op_type == IS_CONST) {
4583        if (Z_TYPE(name_node.u.constant) != IS_STRING) {
4584            convert_to_string(&name_node.u.constant);
4585        }
4586    }
4587
4588    if (zend_try_compile_cv(&result, var_ast TSRMLS_CC) == SUCCESS) {
4589        zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
4590        zend_alloc_cache_slot(opline->op2.constant 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            if (has_default_case) {
5094                CG(zend_lineno) = case_ast->lineno;
5095                zend_error_noreturn(E_COMPILE_ERROR,
5096                    "Switch statements may only contain one default clause");
5097            }
5098            has_default_case = 1;
5099            continue;
5100        }
5101
5102        zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
5103
5104        opline = zend_emit_op(NULL, ZEND_CASE, &expr_node, &cond_node TSRMLS_CC);
5105        SET_NODE(opline->result, &case_node);
5106        if (opline->op1_type == IS_CONST) {
5107            zval_copy_ctor(&CONSTANT(opline->op1.constant));
5108        }
5109
5110        jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0 TSRMLS_CC);
5111    }
5112
5113    opnum_default_jmp = zend_emit_jump(0 TSRMLS_CC);
5114
5115    for (i = 0; i < cases->children; ++i) {
5116        zend_ast *case_ast = cases->child[i];
5117        zend_ast *cond_ast = case_ast->child[0];
5118