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