1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2013 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        && (Z_HASH_P(&CONSTANT(opline->op1.constant)) == THIS_HASHVAL)
912        && (Z_STRLEN(CONSTANT(opline->op1.constant)) == (sizeof("this")-1))
913        && !memcmp(Z_STRVAL(CONSTANT(opline->op1.constant)), "this", sizeof("this"))) {
914        return 1;
915    } else {
916        return 0;
917    }
918}
919/* }}} */
920
921void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */
922{
923    int last_op_number;
924    zend_op *opline;
925
926    if (value->op_type == IS_CV) {
927        zend_llist *fetch_list_ptr;
928
929        zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
930        if (fetch_list_ptr && fetch_list_ptr->head) {
931            opline = (zend_op *)fetch_list_ptr->head->data;
932
933            if (opline->opcode == ZEND_FETCH_DIM_W &&
934                opline->op1_type == IS_CV &&
935                opline->op1.var == value->u.op.var) {
936
937                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
938                opline->opcode = ZEND_FETCH_R;
939                opline->result_type = IS_VAR;
940                opline->result.var = get_temporary_variable(CG(active_op_array));
941                opline->op1_type = IS_CONST;
942                LITERAL_STRINGL(opline->op1,
943                    CG(active_op_array)->vars[value->u.op.var].name,
944                    CG(active_op_array)->vars[value->u.op.var].name_len, 1);
945                CALCULATE_LITERAL_HASH(opline->op1.constant);
946                SET_UNUSED(opline->op2);
947                opline->extended_value = ZEND_FETCH_LOCAL;
948                GET_NODE(value, opline->result);
949            }
950        }
951    }
952
953    zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC);
954
955    last_op_number = get_next_op_number(CG(active_op_array));
956    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
957
958    if (variable->op_type == IS_CV) {
959        if (variable->u.op.var == CG(active_op_array)->this_var) {
960            zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
961        }
962    } else if (variable->op_type == IS_VAR) {
963        int n = 0;
964
965        while (last_op_number - n > 0) {
966            zend_op *last_op;
967
968            last_op = &CG(active_op_array)->opcodes[last_op_number-n-1];
969
970            if (last_op->result_type == IS_VAR &&
971                last_op->result.var == variable->u.op.var) {
972                if (last_op->opcode == ZEND_FETCH_OBJ_W) {
973                    if (n > 0) {
974                        int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
975                        *opline = *last_op;
976                        MAKE_NOP(last_op);
977                        /* last_op = opline; */
978                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
979                        /* get_next_op can realloc, we need to move last_op */
980                        last_op = &CG(active_op_array)->opcodes[opline_no];
981                    }
982                    last_op->opcode = ZEND_ASSIGN_OBJ;
983                    zend_do_op_data(opline, value TSRMLS_CC);
984                    SET_UNUSED(opline->result);
985                    GET_NODE(result, last_op->result);
986                    return;
987                } else if (last_op->opcode == ZEND_FETCH_DIM_W) {
988                    if (n > 0) {
989                        int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
990                        *opline = *last_op;
991                        MAKE_NOP(last_op);
992                        /* last_op = opline; */
993                        /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */
994                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
995                        /* get_next_op can realloc, we need to move last_op */
996                        last_op = &CG(active_op_array)->opcodes[opline_no];
997                    }
998                    last_op->opcode = ZEND_ASSIGN_DIM;
999                    zend_do_op_data(opline, value TSRMLS_CC);
1000                    opline->op2.var = get_temporary_variable(CG(active_op_array));
1001                    opline->op2_type = IS_VAR;
1002                    SET_UNUSED(opline->result);
1003                    GET_NODE(result, last_op->result);
1004                    return;
1005                } else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
1006                    zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1007                } else {
1008                    break;
1009                }
1010            }
1011            n++;
1012        }
1013    }
1014
1015    opline->opcode = ZEND_ASSIGN;
1016    SET_NODE(opline->op1, variable);
1017    SET_NODE(opline->op2, value);
1018    opline->result_type = IS_VAR;
1019    opline->result.var = get_temporary_variable(CG(active_op_array));
1020    GET_NODE(result, opline->result);
1021}
1022/* }}} */
1023
1024void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
1025{
1026    zend_op *opline;
1027
1028    if (lvar->op_type == IS_CV) {
1029        if (lvar->u.op.var == CG(active_op_array)->this_var) {
1030            zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1031        }
1032    } else if (lvar->op_type == IS_VAR) {
1033        int last_op_number = get_next_op_number(CG(active_op_array));
1034
1035        if (last_op_number > 0) {
1036            opline = &CG(active_op_array)->opcodes[last_op_number-1];
1037            if (opline_is_fetch_this(opline TSRMLS_CC)) {
1038                zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1039            }
1040        }
1041    }
1042
1043    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1044    opline->opcode = ZEND_ASSIGN_REF;
1045    if (zend_is_function_or_method_call(rvar)) {
1046        opline->extended_value = ZEND_RETURNS_FUNCTION;
1047    } else if (rvar->EA & ZEND_PARSED_NEW) {
1048        opline->extended_value = ZEND_RETURNS_NEW;
1049    } else {
1050        opline->extended_value = 0;
1051    }
1052    if (result) {
1053        opline->result_type = IS_VAR;
1054        opline->result.var = get_temporary_variable(CG(active_op_array));
1055        GET_NODE(result, opline->result);
1056    } else {
1057        opline->result_type = IS_UNUSED | EXT_TYPE_UNUSED;
1058    }
1059    SET_NODE(opline->op1, lvar);
1060    SET_NODE(opline->op2, rvar);
1061}
1062/* }}} */
1063
1064static inline void do_begin_loop(TSRMLS_D) /* {{{ */
1065{
1066    zend_brk_cont_element *brk_cont_element;
1067    int parent;
1068
1069    parent = CG(context).current_brk_cont;
1070    CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont;
1071    brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
1072    brk_cont_element->start = get_next_op_number(CG(active_op_array));
1073    brk_cont_element->parent = parent;
1074}
1075/* }}} */
1076
1077static inline void do_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */
1078{
1079    if (!has_loop_var) {
1080        /* The start fileld is used to free temporary variables in case of exceptions.
1081         * We won't try to free something of we don't have loop variable.
1082         */
1083        CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1;
1084    }
1085    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr;
1086    CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array));
1087    CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent;
1088}
1089/* }}} */
1090
1091void zend_do_while_cond(const znode *expr, znode *close_bracket_token TSRMLS_DC) /* {{{ */
1092{
1093    int while_cond_op_number = get_next_op_number(CG(active_op_array));
1094    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1095
1096    opline->opcode = ZEND_JMPZ;
1097    SET_NODE(opline->op1, expr);
1098    close_bracket_token->u.op.opline_num = while_cond_op_number;
1099    SET_UNUSED(opline->op2);
1100
1101    do_begin_loop(TSRMLS_C);
1102    INC_BPC(CG(active_op_array));
1103}
1104/* }}} */
1105
1106void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC) /* {{{ */
1107{
1108    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1109
1110    /* add unconditional jump */
1111    opline->opcode = ZEND_JMP;
1112    opline->op1.opline_num = while_token->u.op.opline_num;
1113    SET_UNUSED(opline->op1);
1114    SET_UNUSED(opline->op2);
1115
1116    /* update while's conditional jmp */
1117    CG(active_op_array)->opcodes[close_bracket_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1118
1119    do_end_loop(while_token->u.op.opline_num, 0 TSRMLS_CC);
1120
1121    DEC_BPC(CG(active_op_array));
1122}
1123/* }}} */
1124
1125void zend_do_for_cond(const znode *expr, znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1126{
1127    int for_cond_op_number = get_next_op_number(CG(active_op_array));
1128    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1129
1130    opline->opcode = ZEND_JMPZNZ;
1131    SET_NODE(opline->op1, expr);  /* the conditional expression */
1132    second_semicolon_token->u.op.opline_num = for_cond_op_number;
1133    SET_UNUSED(opline->op2);
1134}
1135/* }}} */
1136
1137void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1138{
1139    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1140
1141    opline->opcode = ZEND_JMP;
1142    opline->op1.opline_num = cond_start->u.op.opline_num;
1143    CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
1144    SET_UNUSED(opline->op1);
1145    SET_UNUSED(opline->op2);
1146
1147    do_begin_loop(TSRMLS_C);
1148
1149    INC_BPC(CG(active_op_array));
1150}
1151/* }}} */
1152
1153void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1154{
1155    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1156
1157    opline->opcode = ZEND_JMP;
1158    opline->op1.opline_num = second_semicolon_token->u.op.opline_num+1;
1159    CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1160    SET_UNUSED(opline->op1);
1161    SET_UNUSED(opline->op2);
1162
1163    do_end_loop(second_semicolon_token->u.op.opline_num+1, 0 TSRMLS_CC);
1164
1165    DEC_BPC(CG(active_op_array));
1166}
1167/* }}} */
1168
1169void zend_do_pre_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1170{
1171    int last_op_number = get_next_op_number(CG(active_op_array));
1172    zend_op *opline;
1173
1174    if (last_op_number > 0) {
1175        zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1176
1177        if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1178            last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ;
1179            last_op->result_type = IS_VAR;
1180            last_op->result.var = get_temporary_variable(CG(active_op_array));
1181            GET_NODE(result, last_op->result);
1182            return;
1183        }
1184    }
1185
1186    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1187    opline->opcode = op;
1188    SET_NODE(opline->op1, op1);
1189    SET_UNUSED(opline->op2);
1190    opline->result_type = IS_VAR;
1191    opline->result.var = get_temporary_variable(CG(active_op_array));
1192    GET_NODE(result, opline->result);
1193}
1194/* }}} */
1195
1196void zend_do_post_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1197{
1198    int last_op_number = get_next_op_number(CG(active_op_array));
1199    zend_op *opline;
1200
1201    if (last_op_number > 0) {
1202        zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1203
1204        if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1205            last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ;
1206            last_op->result_type = IS_TMP_VAR;
1207            last_op->result.var = get_temporary_variable(CG(active_op_array));
1208            GET_NODE(result, last_op->result);
1209            return;
1210        }
1211    }
1212
1213    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1214    opline->opcode = op;
1215    SET_NODE(opline->op1, op1);
1216    SET_UNUSED(opline->op2);
1217    opline->result_type = IS_TMP_VAR;
1218    opline->result.var = get_temporary_variable(CG(active_op_array));
1219    GET_NODE(result, opline->result);
1220}
1221/* }}} */
1222
1223void zend_do_if_cond(const znode *cond, znode *closing_bracket_token TSRMLS_DC) /* {{{ */
1224{
1225    int if_cond_op_number = get_next_op_number(CG(active_op_array));
1226    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1227
1228    opline->opcode = ZEND_JMPZ;
1229    SET_NODE(opline->op1, cond);
1230    closing_bracket_token->u.op.opline_num = if_cond_op_number;
1231    SET_UNUSED(opline->op2);
1232    INC_BPC(CG(active_op_array));
1233}
1234/* }}} */
1235
1236void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC) /* {{{ */
1237{
1238    int if_end_op_number = get_next_op_number(CG(active_op_array));
1239    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1240    zend_llist *jmp_list_ptr;
1241
1242    opline->opcode = ZEND_JMP;
1243    /* save for backpatching */
1244    if (initialize) {
1245        zend_llist jmp_list;
1246
1247        zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
1248        zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
1249    }
1250    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1251    zend_llist_add_element(jmp_list_ptr, &if_end_op_number);
1252
1253    CG(active_op_array)->opcodes[closing_bracket_token->u.op.opline_num].op2.opline_num = if_end_op_number+1;
1254    SET_UNUSED(opline->op1);
1255    SET_UNUSED(opline->op2);
1256}
1257/* }}} */
1258
1259void zend_do_if_end(TSRMLS_D) /* {{{ */
1260{
1261    int next_op_number = get_next_op_number(CG(active_op_array));
1262    zend_llist *jmp_list_ptr;
1263    zend_llist_element *le;
1264
1265    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1266    for (le=jmp_list_ptr->head; le; le = le->next) {
1267        CG(active_op_array)->opcodes[*((int *) le->data)].op1.opline_num = next_op_number;
1268    }
1269    zend_llist_destroy(jmp_list_ptr);
1270    zend_stack_del_top(&CG(bp_stack));
1271    DEC_BPC(CG(active_op_array));
1272}
1273/* }}} */
1274
1275void zend_check_writable_variable(const znode *variable) /* {{{ */
1276{
1277    zend_uint type = variable->EA;
1278
1279    if (type & ZEND_PARSED_METHOD_CALL) {
1280        zend_error(E_COMPILE_ERROR, "Can't use method return value in write context");
1281    }
1282    if (type == ZEND_PARSED_FUNCTION_CALL) {
1283        zend_error(E_COMPILE_ERROR, "Can't use function return value in write context");
1284    }
1285}
1286/* }}} */
1287
1288void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */
1289{
1290    zend_llist fetch_list;
1291
1292    zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0);
1293    zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist));
1294}
1295/* }}} */
1296
1297void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */
1298{
1299    zend_llist *fetch_list_ptr;
1300    zend_llist_element *le;
1301    zend_op *opline = NULL;
1302    zend_op *opline_ptr;
1303    zend_uint this_var = -1;
1304
1305    zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
1306
1307    le = fetch_list_ptr->head;
1308
1309    /* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */
1310
1311    if (le) {
1312        opline_ptr = (zend_op *)le->data;
1313        if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
1314            /* convert to FETCH_?(this) into IS_CV */
1315            if (CG(active_op_array)->last == 0 ||
1316                CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) {
1317
1318                this_var = opline_ptr->result.var;
1319                if (CG(active_op_array)->this_var == -1) {
1320                    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);
1321                    Z_TYPE(CONSTANT(opline_ptr->op1.constant)) = IS_NULL;
1322                } else {
1323                    zend_del_literal(CG(active_op_array), opline_ptr->op1.constant);
1324                }
1325                le = le->next;
1326                if (variable->op_type == IS_VAR &&
1327                    variable->u.op.var == this_var) {
1328                    variable->op_type = IS_CV;
1329                    variable->u.op.var = CG(active_op_array)->this_var;
1330                }
1331            } else if (CG(active_op_array)->this_var == -1) {
1332                CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1, THIS_HASHVAL TSRMLS_CC);
1333            }
1334        }
1335
1336        while (le) {
1337            opline_ptr = (zend_op *)le->data;
1338            if (opline_ptr->opcode == ZEND_SEPARATE) {
1339                if (type != BP_VAR_R && type != BP_VAR_IS) {
1340                    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1341                    memcpy(opline, opline_ptr, sizeof(zend_op));
1342                }
1343                le = le->next;
1344                continue;
1345            }
1346            opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1347            memcpy(opline, opline_ptr, sizeof(zend_op));
1348            if (opline->op1_type == IS_VAR &&
1349                opline->op1.var == this_var) {
1350                opline->op1_type = IS_CV;
1351                opline->op1.var = CG(active_op_array)->this_var;
1352            }
1353            switch (type) {
1354                case BP_VAR_R:
1355                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1356                        zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1357                    }
1358                    opline->opcode -= 3;
1359                    break;
1360                case BP_VAR_W:
1361                    break;
1362                case BP_VAR_RW:
1363                    opline->opcode += 3;
1364                    break;
1365                case BP_VAR_IS:
1366                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1367                        zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1368                    }
1369                    opline->opcode += 6; /* 3+3 */
1370                    break;
1371                case BP_VAR_FUNC_ARG:
1372                    opline->opcode += 9; /* 3+3+3 */
1373                    opline->extended_value |= arg_offset;
1374                    break;
1375                case BP_VAR_UNSET:
1376                    if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1377                        zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting");
1378                    }
1379                    opline->opcode += 12; /* 3+3+3+3 */
1380                    break;
1381            }
1382            le = le->next;
1383        }
1384        if (opline && type == BP_VAR_W && arg_offset) {
1385            opline->extended_value |= ZEND_FETCH_MAKE_REF;
1386        }
1387    }
1388    zend_llist_destroy(fetch_list_ptr);
1389    zend_stack_del_top(&CG(bp_stack));
1390}
1391/* }}} */
1392
1393void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
1394{
1395    zend_op *opline;
1396
1397    if (Z_STRLEN(op2->u.constant) > 1) {
1398        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1399        opline->opcode = ZEND_ADD_STRING;
1400    } else if (Z_STRLEN(op2->u.constant) == 1) {
1401        int ch = *Z_STRVAL(op2->u.constant);
1402
1403        /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */
1404        efree(Z_STRVAL(op2->u.constant));
1405        ZVAL_LONG(&op2->u.constant, ch);
1406        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1407        opline->opcode = ZEND_ADD_CHAR;
1408    } else { /* String can be empty after a variable at the end of a heredoc */
1409        efree(Z_STRVAL(op2->u.constant));
1410        return;
1411    }
1412
1413    if (op1) {
1414        SET_NODE(opline->op1, op1);
1415        SET_NODE(opline->result, op1);
1416    } else {
1417        SET_UNUSED(opline->op1);
1418        opline->result_type = IS_TMP_VAR;
1419        opline->result.var = get_temporary_variable(CG(active_op_array));
1420    }
1421    SET_NODE(opline->op2, op2);
1422    GET_NODE(result, opline->result);
1423}
1424/* }}} */
1425
1426void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
1427{
1428    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1429
1430    opline->opcode = ZEND_ADD_VAR;
1431
1432    if (op1) {
1433        SET_NODE(opline->op1, op1);
1434        SET_NODE(opline->result, op1);
1435    } else {
1436        SET_UNUSED(opline->op1);
1437        opline->result_type = IS_TMP_VAR;
1438        opline->result.var = get_temporary_variable(CG(active_op_array));
1439    }
1440    SET_NODE(opline->op2, op2);
1441    GET_NODE(result, opline->result);
1442}
1443/* }}} */
1444
1445void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
1446{
1447    if (op1->op_type==IS_TMP_VAR) {
1448        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1449
1450        opline->opcode = ZEND_FREE;
1451        SET_NODE(opline->op1, op1);
1452        SET_UNUSED(opline->op2);
1453    } else if (op1->op_type==IS_VAR) {
1454        zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
1455
1456        while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) {
1457            opline--;
1458        }
1459        if (opline->result_type == IS_VAR
1460            && opline->result.var == op1->u.op.var) {
1461            if (opline->opcode == ZEND_FETCH_R ||
1462                opline->opcode == ZEND_FETCH_DIM_R ||
1463                opline->opcode == ZEND_FETCH_OBJ_R ||
1464                opline->opcode == ZEND_QM_ASSIGN_VAR) {
1465                /* It's very rare and useless case. It's better to use
1466                   additional FREE opcode and simplify the FETCH handlers
1467                   their selves */
1468                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1469                opline->opcode = ZEND_FREE;
1470                SET_NODE(opline->op1, op1);
1471                SET_UNUSED(opline->op2);
1472            } else {
1473                opline->result_type |= EXT_TYPE_UNUSED;
1474            }
1475        } else {
1476            while (opline>CG(active_op_array)->opcodes) {
1477                if (opline->opcode == ZEND_FETCH_DIM_R
1478                    && opline->op1_type == IS_VAR
1479                    && opline->op1.var == op1->u.op.var) {
1480                    /* This should the end of a list() construct
1481                     * Mark its result as unused
1482                     */
1483                    opline->extended_value = ZEND_FETCH_STANDARD;
1484                    break;
1485                } else if (opline->result_type==IS_VAR
1486                    && opline->result.var == op1->u.op.var) {
1487                    if (opline->opcode == ZEND_NEW) {
1488                        opline->result_type |= EXT_TYPE_UNUSED;
1489                    }
1490                    break;
1491                }
1492                opline--;
1493            }
1494        }
1495    } else if (op1->op_type == IS_CONST) {
1496        zval_dtor(&op1->u.constant);
1497    }
1498}
1499/* }}} */
1500
1501int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier) /* {{{ */
1502{
1503    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_PPP_MASK)
1504        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_PPP_MASK)) {
1505        zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
1506    }
1507    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_ABSTRACT)
1508        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_ABSTRACT)) {
1509        zend_error(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
1510    }
1511    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_STATIC)
1512        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_STATIC)) {
1513        zend_error(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
1514    }
1515    if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_FINAL)
1516        && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_FINAL)) {
1517        zend_error(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
1518    }
1519    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)) {
1520        zend_error(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
1521    }
1522    return (Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant));
1523}
1524/* }}} */
1525
1526void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
1527{
1528    zend_op_array op_array;
1529    char *name = function_name->u.constant.value.str.val;
1530    int name_len = function_name->u.constant.value.str.len;
1531    int function_begin_line = function_token->u.op.opline_num;
1532    zend_uint fn_flags;
1533    const char *lcname;
1534    zend_bool orig_interactive;
1535    ALLOCA_FLAG(use_heap)
1536
1537    if (is_method) {
1538        if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1539            if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) {
1540                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);
1541            }
1542            Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
1543        }
1544        fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
1545    } else {
1546        fn_flags = 0;
1547    }
1548    if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
1549        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));
1550    }
1551
1552    function_token->u.op_array = CG(active_op_array);
1553
1554    orig_interactive = CG(interactive);
1555    CG(interactive) = 0;
1556    init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
1557    CG(interactive) = orig_interactive;
1558
1559    op_array.function_name = name;
1560    if (return_reference) {
1561        op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1562    }
1563    op_array.fn_flags |= fn_flags;
1564
1565    op_array.scope = is_method?CG(active_class_entry):NULL;
1566    op_array.prototype = NULL;
1567
1568    op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);
1569
1570    if (is_method) {
1571        int result;
1572
1573        lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);
1574
1575        if (IS_INTERNED(lcname)) {
1576            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));
1577        } else {
1578            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));
1579        }
1580        if (result == FAILURE) {
1581            zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
1582        }
1583
1584        zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1585        zend_init_compiler_context(TSRMLS_C);
1586
1587        if (fn_flags & ZEND_ACC_ABSTRACT) {
1588            CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1589        }
1590
1591        if (!(fn_flags & ZEND_ACC_PPP_MASK)) {
1592            fn_flags |= ZEND_ACC_PUBLIC;
1593        }
1594
1595        if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1596            if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1597                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1598                    zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1599                }
1600            } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1601                if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1602                    zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1603                }
1604            } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1605                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1606                    zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1607                }
1608            } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1609                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1610                    zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1611                }
1612            } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1613                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1614                    zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1615                }
1616            } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1617                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1618                    zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1619                }
1620            } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1621                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1622                    zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1623                }
1624            } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1625                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1626                    zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1627                }
1628            }
1629        } else {
1630            char *class_lcname;
1631
1632            class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
1633            zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
1634            /* Improve after RC: cache the lowercase class name */
1635
1636            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))) {
1637                if (!CG(active_class_entry)->constructor) {
1638                    CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1639                }
1640            } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) {
1641                if (CG(active_class_entry)->constructor) {
1642                    zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name);
1643                }
1644                CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1645            } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) {
1646                CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array);
1647            } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) {
1648                CG(active_class_entry)->clone = (zend_function *) CG(active_op_array);
1649            } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1650                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1651                    zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1652                }
1653                CG(active_class_entry)->__call = (zend_function *) CG(active_op_array);
1654            } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1655                if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1656                    zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1657                }
1658                CG(active_class_entry)->__callstatic = (zend_function *) CG(active_op_array);
1659            } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1660                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1661                    zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1662                }
1663                CG(active_class_entry)->__get = (zend_function *) CG(active_op_array);
1664            } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1665                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1666                    zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1667                }
1668                CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
1669            } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1670                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1671                    zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1672                }
1673                CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array);
1674            } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1675                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1676                    zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1677                }
1678                CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
1679            } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1680                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1681                    zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1682                }
1683                CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
1684            } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1685                if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1686                    zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1687                }
1688            } else if (!(fn_flags & ZEND_ACC_STATIC)) {
1689                CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
1690            }
1691            free_alloca(class_lcname, use_heap);
1692        }
1693
1694        str_efree(lcname);
1695    } else {
1696        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1697        zval key;
1698
1699        if (CG(current_namespace)) {
1700            /* Prefix function name with current namespace name */
1701            znode tmp;
1702
1703            tmp.u.constant = *CG(current_namespace);
1704            zval_copy_ctor(&tmp.u.constant);
1705            zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
1706            op_array.function_name = Z_STRVAL(tmp.u.constant);
1707            name_len = Z_STRLEN(tmp.u.constant);
1708            lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
1709        } else {
1710            lcname = zend_str_tolower_dup(name, name_len);
1711        }
1712
1713        opline->opcode = ZEND_DECLARE_FUNCTION;
1714        opline->op1_type = IS_CONST;
1715        build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC);
1716        opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
1717        Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
1718        opline->op2_type = IS_CONST;
1719        LITERAL_STRINGL(opline->op2, lcname, name_len, 0);
1720        CALCULATE_LITERAL_HASH(opline->op2.constant);
1721        opline->extended_value = ZEND_DECLARE_FUNCTION;
1722        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));
1723        zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1724        zend_init_compiler_context(TSRMLS_C);
1725    }
1726
1727    if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
1728        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1729
1730        opline->opcode = ZEND_EXT_NOP;
1731        opline->lineno = function_begin_line;
1732        SET_UNUSED(opline->op1);
1733        SET_UNUSED(opline->op2);
1734    }
1735
1736    {
1737        /* Push a seperator to the switch stack */
1738        zend_switch_entry switch_entry;
1739
1740        switch_entry.cond.op_type = IS_UNUSED;
1741        switch_entry.default_case = 0;
1742        switch_entry.control_var = 0;
1743
1744        zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
1745    }
1746
1747    {
1748        /* Push a separator to the foreach stack */
1749        zend_op dummy_opline;
1750
1751        dummy_opline.result_type = IS_UNUSED;
1752        dummy_opline.op1_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 seperators */
1832    zend_stack_del_top(&CG(switch_cond_stack));
1833    zend_stack_del_top(&CG(foreach_copy_stack));
1834}
1835/* }}} */
1836
1837void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
1838{
1839    zend_op *opline;
1840    zend_arg_info *cur_arg_info;
1841    znode var;
1842
1843    if (class_type->op_type == IS_CONST &&
1844        Z_TYPE(class_type->u.constant) == IS_STRING &&
1845        Z_STRLEN(class_type->u.constant) == 0) {
1846        /* Usage of namespace as class name not in namespace */
1847        zval_dtor(&class_type->u.constant);
1848        zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
1849        return;
1850    }
1851
1852    if (zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0 TSRMLS_CC)) {
1853        zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
1854    } else {
1855        var.op_type = IS_CV;
1856        var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, 0 TSRMLS_CC);
1857        Z_STRVAL(varname->u.constant) = (char*)CG(active_op_array)->vars[var.u.op.var].name;
1858        var.EA = 0;
1859        if (CG(active_op_array)->vars[var.u.op.var].hash_value == THIS_HASHVAL &&
1860            Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
1861            !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
1862            if (CG(active_op_array)->scope &&
1863                (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
1864                zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1865            }
1866            CG(active_op_array)->this_var = var.u.op.var;
1867        }
1868    }
1869
1870    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1871    CG(active_op_array)->num_args++;
1872    opline->opcode = op;
1873    SET_NODE(opline->result, &var);
1874    SET_NODE(opline->op1, offset);
1875    if (op == ZEND_RECV_INIT) {
1876        SET_NODE(opline->op2, initialization);
1877    } else {
1878        CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
1879        SET_UNUSED(opline->op2);
1880    }
1881    CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
1882    cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
1883    cur_arg_info->name = zend_new_interned_string(estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len), varname->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1884    cur_arg_info->name_len = varname->u.constant.value.str.len;
1885    cur_arg_info->type_hint = 0;
1886    cur_arg_info->allow_null = 1;
1887    cur_arg_info->pass_by_reference = pass_by_reference;
1888    cur_arg_info->class_name = NULL;
1889    cur_arg_info->class_name_len = 0;
1890
1891    if (class_type->op_type != IS_UNUSED) {
1892        cur_arg_info->allow_null = 0;
1893
1894        if (class_type->u.constant.type != IS_NULL) {
1895            if (class_type->u.constant.type == IS_ARRAY) {
1896                cur_arg_info->type_hint = IS_ARRAY;
1897                if (op == ZEND_RECV_INIT) {
1898                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1899                        cur_arg_info->allow_null = 1;
1900                    } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY && Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) {
1901                        zend_error(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL");
1902                    }
1903                }
1904            } else if (class_type->u.constant.type == IS_CALLABLE) {
1905                cur_arg_info->type_hint = IS_CALLABLE;
1906                if (op == ZEND_RECV_INIT) {
1907                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1908                        cur_arg_info->allow_null = 1;
1909                    } else {
1910                        zend_error(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
1911                    }
1912                }
1913            } else {
1914                cur_arg_info->type_hint = IS_OBJECT;
1915                if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) {
1916                    zend_resolve_class_name(class_type, opline->extended_value, 1 TSRMLS_CC);
1917                }
1918                Z_STRVAL(class_type->u.constant) = (char*)zend_new_interned_string(class_type->u.constant.value.str.val, class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1919                cur_arg_info->class_name = class_type->u.constant.value.str.val;
1920                cur_arg_info->class_name_len = class_type->u.constant.value.str.len;
1921                if (op == ZEND_RECV_INIT) {
1922                    if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1923                        cur_arg_info->allow_null = 1;
1924                    } else {
1925                        zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL");
1926                    }
1927                }
1928            }
1929        }
1930    }
1931}
1932/* }}} */
1933
1934int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
1935{
1936    zend_function *function;
1937    char *lcname;
1938    char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
1939
1940    zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC);
1941
1942    if (check_namespace && CG(current_namespace) && !is_compound) {
1943            /* We assume we call function from the current namespace
1944            if it is not prefixed. */
1945
1946            /* In run-time PHP will check for function with full name and
1947            internal function with short name */
1948            zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
1949            return 1;
1950    }
1951
1952    lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
1953    if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
1954        ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
1955        (function->type == ZEND_INTERNAL_FUNCTION))) {
1956            zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
1957            efree(lcname);
1958            return 1; /* Dynamic */
1959    }
1960    efree(function_name->u.constant.value.str.val);
1961    function_name->u.constant.value.str.val = lcname;
1962
1963    zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
1964    if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
1965        CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
1966    }
1967    zend_do_extended_fcall_begin(TSRMLS_C);
1968    return 0;
1969}
1970/* }}} */
1971
1972void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
1973{
1974    zend_op *last_op;
1975    int last_op_number;
1976    unsigned char *ptr = NULL;
1977
1978    zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC);
1979    zend_do_begin_variable_parse(TSRMLS_C);
1980
1981    last_op_number = get_next_op_number(CG(active_op_array))-1;
1982    last_op = &CG(active_op_array)->opcodes[last_op_number];
1983
1984    if ((last_op->op2_type == IS_CONST) && (Z_TYPE(CONSTANT(last_op->op2.constant)) == IS_STRING) && (Z_STRLEN(CONSTANT(last_op->op2.constant)) == sizeof(ZEND_CLONE_FUNC_NAME)-1)
1985        && !zend_binary_strcasecmp(Z_STRVAL(CONSTANT(last_op->op2.constant)), Z_STRLEN(CONSTANT(last_op->op2.constant)), ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) {
1986        zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead");
1987    }
1988
1989    if (last_op->opcode == ZEND_FETCH_OBJ_R) {
1990        if (last_op->op2_type == IS_CONST) {
1991            zval name;
1992            name = CONSTANT(last_op->op2.constant);
1993            if (Z_TYPE(name) != IS_STRING) {
1994                zend_error(E_COMPILE_ERROR, "Method name must be a string");
1995            }
1996            if (!IS_INTERNED(Z_STRVAL(name))) {
1997                Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
1998            }
1999            FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2000            last_op->op2.constant =
2001                zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC);
2002            GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2003        }
2004        last_op->opcode = ZEND_INIT_METHOD_CALL;
2005        last_op->result_type = IS_UNUSED;
2006        last_op->result.num = CG(context).nested_calls;
2007        Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
2008    } else {
2009        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2010        opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2011        opline->result.num = CG(context).nested_calls;
2012        SET_UNUSED(opline->op1);
2013        if (left_bracket->op_type == IS_CONST) {
2014            opline->op2_type = IS_CONST;
2015            opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC);
2016            GET_CACHE_SLOT(opline->op2.constant);
2017        } else {
2018            SET_NODE(opline->op2, left_bracket);
2019        }
2020    }
2021
2022    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2023    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2024        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2025    }
2026    zend_do_extended_fcall_begin(TSRMLS_C);
2027}
2028/* }}} */
2029
2030void zend_do_clone(znode *result, const znode *expr TSRMLS_DC) /* {{{ */
2031{
2032    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2033
2034    opline->opcode = ZEND_CLONE;
2035    SET_NODE(opline->op1, expr);
2036    SET_UNUSED(opline->op2);
2037    opline->result_type = IS_VAR;
2038    opline->result.var = get_temporary_variable(CG(active_op_array));
2039    GET_NODE(result, opline->result);
2040}
2041/* }}} */
2042
2043void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */
2044{
2045    unsigned char *ptr = NULL;
2046    zend_op *opline;
2047
2048    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2049    if (ns_call) {
2050        /* In run-time PHP will check for function with full name and
2051           internal function with short name */
2052        opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
2053        opline->result.num = CG(context).nested_calls;
2054        SET_UNUSED(opline->op1);
2055        opline->op2_type = IS_CONST;
2056        opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2057        GET_CACHE_SLOT(opline->op2.constant);
2058    } else {
2059        opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2060        opline->result.num = CG(context).nested_calls;
2061        SET_UNUSED(opline->op1);
2062        if (function_name->op_type == IS_CONST) {
2063            opline->op2_type = IS_CONST;
2064            opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2065            GET_CACHE_SLOT(opline->op2.constant);
2066        } else {
2067            SET_NODE(opline->op2, function_name);
2068        }
2069    }
2070
2071    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2072    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2073        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2074    }
2075    zend_do_extended_fcall_begin(TSRMLS_C);
2076}
2077/* }}} */
2078
2079void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
2080{
2081    znode tmp;
2082    int len;
2083    zval **ns;
2084    char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant));
2085
2086    if (Z_STRVAL(element_name->u.constant)[0] == '\\') {
2087        /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */
2088        memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant));
2089        --Z_STRLEN(element_name->u.constant);
2090        return;
2091    }
2092
2093    if(!check_namespace) {
2094        return;
2095    }
2096
2097    if (compound && CG(current_import)) {
2098        len = compound - Z_STRVAL(element_name->u.constant);
2099        lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len);
2100        /* Check if first part of compound name is an import name */
2101        if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2102            /* Substitute import name */
2103            tmp.op_type = IS_CONST;
2104            tmp.u.constant = **ns;
2105            zval_copy_ctor(&tmp.u.constant);
2106            len += 1;
2107            Z_STRLEN(element_name->u.constant) -= len;
2108            memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1);
2109            zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC);
2110            *element_name = tmp;
2111            efree(lcname);
2112            return;
2113        }
2114        efree(lcname);
2115    }
2116
2117    if (CG(current_namespace)) {
2118        tmp = *element_name;
2119        Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace));
2120        Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1);
2121        memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
2122        memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1);
2123        memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1);
2124        STR_FREE(Z_STRVAL(element_name->u.constant));
2125        *element_name = tmp;
2126    }
2127}
2128/* }}} */
2129
2130void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */
2131{
2132    char *lcname;
2133    int lctype;
2134    znode constant_name;
2135
2136    lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len);
2137    lctype = zend_get_class_fetch_type(lcname, strlen(lcname));
2138    switch (lctype) {
2139        case ZEND_FETCH_CLASS_SELF:
2140            if (!CG(active_class_entry)) {
2141                zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active");
2142            }
2143            zval_dtor(&class_name->u.constant);
2144            class_name->op_type = IS_CONST;
2145            ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1);
2146            *result = *class_name;
2147            break;
2148        case ZEND_FETCH_CLASS_STATIC:
2149        case ZEND_FETCH_CLASS_PARENT:
2150            if (is_static) {
2151                zend_error(E_COMPILE_ERROR,
2152                    "%s::class cannot be used for compile-time class name resolution",
2153                    lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2154                    );
2155            }
2156            if (!CG(active_class_entry)) {
2157                zend_error(E_COMPILE_ERROR,
2158                    "Cannot access %s::class when no class scope is active",
2159                    lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2160                    );
2161            }
2162            constant_name.op_type = IS_CONST;
2163            ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
2164            zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
2165            break;
2166        case ZEND_FETCH_CLASS_DEFAULT:
2167            zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2168            *result = *class_name;
2169            break;
2170    }
2171
2172    efree(lcname);
2173
2174}
2175/* }}} */
2176
2177void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */
2178{
2179    char *compound;
2180    char *lcname;
2181    zval **ns;
2182    znode tmp;
2183    int len;
2184
2185    compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant));
2186    if (compound) {
2187        /* This is a compound class name that contains namespace prefix */
2188        if (Z_STRVAL(class_name->u.constant)[0] == '\\') {
2189            /* The STRING name has "\" prefix */
2190            Z_STRLEN(class_name->u.constant) -= 1;
2191            memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1);
2192            Z_STRVAL(class_name->u.constant) = erealloc(
2193            Z_STRVAL(class_name->u.constant),
2194            Z_STRLEN(class_name->u.constant) + 1);
2195
2196            if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2197                zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant));
2198            }
2199        } else {
2200            if (CG(current_import)) {
2201                len = compound - Z_STRVAL(class_name->u.constant);
2202                lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len);
2203                /* Check if first part of compound name is an import name */
2204                if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2205                    /* Substitute import name */
2206                    tmp.op_type = IS_CONST;
2207                    tmp.u.constant = **ns;
2208                    zval_copy_ctor(&tmp.u.constant);
2209                    len += 1;
2210                    Z_STRLEN(class_name->u.constant) -= len;
2211                    memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1);
2212                    zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2213                    *class_name = tmp;
2214                    efree(lcname);
2215                    return;
2216                }
2217                efree(lcname);
2218            }
2219            /* Here name is not prefixed with \ and not imported */
2220            if (CG(current_namespace)) {
2221                tmp.op_type = IS_CONST;
2222                tmp.u.constant = *CG(current_namespace);
2223                zval_copy_ctor(&tmp.u.constant);
2224                zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2225                *class_name = tmp;
2226            }
2227        }
2228    } else if (CG(current_import) || CG(current_namespace)) {
2229        /* this is a plain name (without \) */
2230        lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
2231
2232        if (CG(current_import) &&
2233            zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns) == SUCCESS) {
2234            /* The given name is an import name. Substitute it. */
2235            zval_dtor(&class_name->u.constant);
2236            class_name->u.constant = **ns;
2237            zval_copy_ctor(&class_name->u.constant);
2238        } else if (CG(current_namespace)) {
2239            /* plain name, no import - prepend current namespace to it */
2240            tmp.op_type = IS_CONST;
2241            tmp.u.constant = *CG(current_namespace);
2242            zval_copy_ctor(&tmp.u.constant);
2243            zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2244            *class_name = tmp;
2245        }
2246        efree(lcname);
2247    }
2248}
2249/* }}} */
2250
2251void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
2252{
2253    long fetch_class_op_number;
2254    zend_op *opline;
2255
2256    if (class_name->op_type == IS_CONST &&
2257        Z_TYPE(class_name->u.constant) == IS_STRING &&
2258        Z_STRLEN(class_name->u.constant) == 0) {
2259        /* Usage of namespace as class name not in namespace */
2260        zval_dtor(&class_name->u.constant);
2261        zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
2262        return;
2263    }
2264
2265    fetch_class_op_number = get_next_op_number(CG(active_op_array));
2266    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2267
2268    opline->opcode = ZEND_FETCH_CLASS;
2269    SET_UNUSED(opline->op1);
2270    opline->extended_value = ZEND_FETCH_CLASS_GLOBAL;
2271    CG(catch_begin) = fetch_class_op_number;
2272    if (class_name->op_type == IS_CONST) {
2273        int fetch_type;
2274
2275        fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
2276        switch (fetch_type) {
2277            case ZEND_FETCH_CLASS_SELF:
2278            case ZEND_FETCH_CLASS_PARENT:
2279            case ZEND_FETCH_CLASS_STATIC:
2280                SET_UNUSED(opline->op2);
2281                opline->extended_value = fetch_type;
2282                zval_dtor(&class_name->u.constant);
2283                break;
2284            default:
2285                zend_resolve_class_name(class_name, opline->extended_value, 0 TSRMLS_CC);
2286                opline->op2_type = IS_CONST;
2287                opline->op2.constant =
2288                    zend_add_class_name_literal(CG(active_op_array), &class_name->u.constant TSRMLS_CC);
2289                break;
2290        }
2291    } else {
2292        SET_NODE(opline->op2, class_name);
2293    }
2294    opline->result.var = get_temporary_variable(CG(active_op_array));
2295    opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */
2296    GET_NODE(result, opline->result);
2297    result->EA = opline->extended_value;
2298}
2299/* }}} */
2300
2301void zend_do_label(znode *label TSRMLS_DC) /* {{{ */
2302{
2303    zend_label dest;
2304
2305    if (!CG(context).labels) {
2306        ALLOC_HASHTABLE(CG(context).labels);
2307        zend_hash_init(CG(context).labels, 4, NULL, NULL, 0);
2308    }
2309
2310    dest.brk_cont = CG(context).current_brk_cont;
2311    dest.opline_num = get_next_op_number(CG(active_op_array));
2312
2313    if (zend_hash_add(CG(context).labels, Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) {
2314        zend_error(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL(label->u.constant));
2315    }
2316
2317    /* Done with label now */
2318    zval_dtor(&label->u.constant);
2319}
2320/* }}} */
2321
2322void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */
2323{
2324    zend_label *dest;
2325    long current, distance;
2326    zval *label;
2327
2328    if (pass2) {
2329        label = opline->op2.zv;
2330    } else {
2331        label = &CONSTANT_EX(op_array, opline->op2.constant);
2332    }
2333    if (CG(context).labels == NULL ||
2334        zend_hash_find(CG(context).labels, Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) {
2335
2336        if (pass2) {
2337            CG(in_compilation) = 1;
2338            CG(active_op_array) = op_array;
2339            CG(zend_lineno) = opline->lineno;
2340            zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
2341        } else {
2342            /* Label is not defined. Delay to pass 2. */
2343            INC_BPC(op_array);
2344            return;
2345        }
2346    }
2347
2348    opline->op1.opline_num = dest->opline_num;
2349    zval_dtor(label);
2350    Z_TYPE_P(label) = IS_NULL;
2351
2352    /* Check that we are not moving into loop or switch */
2353    current = opline->extended_value;
2354    for (distance = 0; current != dest->brk_cont; distance++) {
2355        if (current == -1) {
2356            if (pass2) {
2357                CG(in_compilation) = 1;
2358                CG(active_op_array) = op_array;
2359                CG(zend_lineno) = opline->lineno;
2360            }
2361            zend_error(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
2362        }
2363        current = op_array->brk_cont_array[current].parent;
2364    }
2365
2366    if (distance == 0) {
2367        /* Nothing to break out of, optimize to ZEND_JMP */
2368        opline->opcode = ZEND_JMP;
2369        opline->extended_value = 0;
2370        SET_UNUSED(opline->op2);
2371    } else {
2372        /* Set real break distance */
2373        ZVAL_LONG(label, distance);
2374    }
2375
2376    if (pass2) {
2377        DEC_BPC(op_array);
2378    }
2379}
2380/* }}} */
2381
2382void zend_do_goto(const znode *label TSRMLS_DC) /* {{{ */
2383{
2384    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2385
2386    opline->opcode = ZEND_GOTO;
2387    opline->extended_value = CG(context).current_brk_cont;
2388    SET_UNUSED(opline->op1);
2389    SET_NODE(opline->op2, label);
2390    zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC);
2391}
2392/* }}} */
2393
2394void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
2395{
2396    if (CG(context).labels) {
2397        zend_hash_destroy(CG(context).labels);
2398        FREE_HASHTABLE(CG(context).labels);
2399        CG(context).labels = NULL;
2400    }
2401    if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
2402        zend_compiler_context *ctx;
2403
2404        zend_stack_top(&CG(context_stack), (void**)&ctx);
2405        CG(context) = *ctx;
2406        zend_stack_del_top(&CG(context_stack));
2407    }
2408}
2409/* }}} */
2410
2411void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC) /* {{{ */
2412{
2413    zend_uint length;
2414
2415    if (!result) {
2416        result = prefix;
2417    } else {
2418        *result = *prefix;
2419    }
2420
2421    if (is_class_member) {
2422        length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2423        result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2424        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1);
2425        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2426        STR_FREE(name->u.constant.value.str.val);
2427        result->u.constant.value.str.len = length;
2428    } else {
2429        length = sizeof("\\")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2430        result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2431        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "\\", sizeof("\\")-1);
2432        memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("\\")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2433        STR_FREE(name->u.constant.value.str.val);
2434        result->u.constant.value.str.len = length;
2435    }
2436}
2437/* }}} */
2438
2439int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
2440{
2441    znode class_node;
2442    unsigned char *ptr = NULL;
2443    zend_op *opline;
2444
2445    if (method_name->op_type == IS_CONST) {
2446        char *lcname;
2447        if (Z_TYPE(method_name->u.constant) != IS_STRING) {
2448            zend_error(E_COMPILE_ERROR, "Method name must be a string");
2449        }
2450        lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant));
2451        if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) &&
2452            memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) {
2453            zval_dtor(&method_name->u.constant);
2454            method_name->op_type = IS_UNUSED;
2455        }
2456        efree(lcname);
2457    }
2458
2459    if (class_name->op_type == IS_CONST &&
2460        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2461        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2462        class_node = *class_name;
2463        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2464    } else {
2465        zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
2466        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2467        opline->extended_value = class_node.EA  ;
2468    }
2469    opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
2470    opline->result.num = CG(context).nested_calls;
2471    if (class_node.op_type == IS_CONST) {
2472        opline->op1_type = IS_CONST;
2473        opline->op1.constant =
2474            zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
2475    } else {
2476        SET_NODE(opline->op1, &class_node);
2477    }
2478    if (method_name->op_type == IS_CONST) {
2479        opline->op2_type = IS_CONST;
2480        opline->op2.constant =
2481            zend_add_func_name_literal(CG(active_op_array), &method_name->u.constant TSRMLS_CC);
2482        if (opline->op1_type == IS_CONST) {
2483            GET_CACHE_SLOT(opline->op2.constant);
2484        } else {
2485            GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
2486        }
2487    } else {
2488        SET_NODE(opline->op2, method_name);
2489    }
2490
2491    zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2492    if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2493        CG(active_op_array)->nested_calls = CG(context).nested_calls;
2494    }
2495    zend_do_extended_fcall_begin(TSRMLS_C);
2496    return 1; /* Dynamic */
2497}
2498/* }}} */
2499
2500void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
2501{
2502    zend_op *opline;
2503
2504    if (is_method && function_name && function_name->op_type == IS_UNUSED) {
2505        /* clone */
2506        if (Z_LVAL(argument_list->u.constant) != 0) {
2507            zend_error(E_WARNING, "Clone method does not require arguments");
2508        }
2509        opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
2510    } else {
2511        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2512        if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
2513            opline->opcode = ZEND_DO_FCALL;
2514            SET_NODE(opline->op1, function_name);
2515            SET_UNUSED(opline->op2);
2516            opline->op2.num = CG(context).nested_calls;
2517            CALCULATE_LITERAL_HASH(opline->op1.constant);
2518            GET_CACHE_SLOT(opline->op1.constant);
2519        } else {
2520            opline->opcode = ZEND_DO_FCALL_BY_NAME;
2521            SET_UNUSED(opline->op1);
2522            SET_UNUSED(opline->op2);
2523            opline->op2.num = --CG(context).nested_calls;
2524        }
2525    }
2526
2527    opline->result.var = get_temporary_variable(CG(active_op_array));
2528    opline->result_type = IS_VAR;
2529    GET_NODE(result, opline->result);
2530
2531    zend_stack_del_top(&CG(function_call_stack));
2532    opline->extended_value = Z_LVAL(argument_list->u.constant);
2533
2534    if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
2535        CG(active_op_array)->used_stack = CG(context).used_stack + 1;
2536    }
2537    CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
2538}
2539/* }}} */
2540
2541void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */
2542{
2543    zend_op *opline;
2544    int original_op=op;
2545    zend_function **function_ptr_ptr, *function_ptr;
2546    int send_by_reference;
2547    int send_function = 0;
2548
2549    zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
2550    function_ptr = *function_ptr_ptr;
2551
2552    if (original_op == ZEND_SEND_REF) {
2553        if (function_ptr &&
2554            function_ptr->common.function_name &&
2555            function_ptr->common.type == ZEND_USER_FUNCTION &&
2556            !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2557            zend_error(E_COMPILE_ERROR,
2558                        "Call-time pass-by-reference has been removed; "
2559                        "If you would like to pass argument by reference, modify the declaration of %s().",
2560                        function_ptr->common.function_name);
2561        } else {
2562            zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed");
2563        }
2564        return;
2565    }
2566
2567    if (function_ptr) {
2568        if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2569            if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
2570                send_by_reference = 1;
2571                if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2572                    /* Method call */
2573                    op = ZEND_SEND_VAR_NO_REF;
2574                    send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT;
2575                }
2576            } else {
2577                op = ZEND_SEND_VAL;
2578                send_by_reference = 0;
2579            }
2580        } else {
2581            send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0;
2582        }
2583    } else {
2584        send_by_reference = 0;
2585    }
2586
2587    if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2588        /* Method call */
2589        op = ZEND_SEND_VAR_NO_REF;
2590        send_function = ZEND_ARG_SEND_FUNCTION;
2591    } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) {
2592        op = ZEND_SEND_VAR_NO_REF;
2593    }
2594
2595    if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) {
2596        /* change to passing by reference */
2597        switch (param->op_type) {
2598            case IS_VAR:
2599            case IS_CV:
2600                op = ZEND_SEND_REF;
2601                break;
2602            default:
2603                zend_error(E_COMPILE_ERROR, "Only variables can be passed by reference");
2604                break;
2605        }
2606    }
2607
2608    if (original_op == ZEND_SEND_VAR) {
2609        switch (op) {
2610            case ZEND_SEND_VAR_NO_REF:
2611                zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2612                break;
2613            case ZEND_SEND_VAR:
2614                if (function_ptr) {
2615                    zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2616                } else {
2617                    zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC);
2618                }
2619                break;
2620            case ZEND_SEND_REF:
2621                zend_do_end_variable_parse(param, BP_VAR_W, 0 TSRMLS_CC);
2622                break;
2623        }
2624    }
2625
2626    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2627
2628    if (op == ZEND_SEND_VAR_NO_REF) {
2629        if (function_ptr) {
2630            opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference | send_function;
2631        } else {
2632            opline->extended_value = send_function;
2633        }
2634    } else {
2635        if (function_ptr) {
2636            opline->extended_value = ZEND_DO_FCALL;
2637        } else {
2638            opline->extended_value = ZEND_DO_FCALL_BY_NAME;
2639        }
2640    }
2641    opline->opcode = op;
2642    SET_NODE(opline->op1, param);
2643    opline->op2.opline_num = offset;
2644    SET_UNUSED(opline->op2);
2645
2646    if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
2647        CG(active_op_array)->used_stack = CG(context).used_stack;
2648    }
2649}
2650/* }}} */
2651
2652static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */
2653{
2654    zend_op *opline;
2655
2656    if (switch_entry->cond.op_type != IS_VAR && switch_entry->cond.op_type != IS_TMP_VAR) {
2657        return (switch_entry->cond.op_type == IS_UNUSED);
2658    }
2659
2660    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2661
2662    opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2663    SET_NODE(opline->op1, &switch_entry->cond);
2664    SET_UNUSED(opline->op2);
2665    opline->extended_value = 0;
2666    return 0;
2667}
2668/* }}} */
2669
2670static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /* {{{ */
2671{
2672    zend_op *opline;
2673
2674    /* If we reach the seperator then stop applying the stack */
2675    if (foreach_copy->result_type == IS_UNUSED && foreach_copy->op1_type == IS_UNUSED) {
2676        return 1;
2677    }
2678
2679    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2680
2681    opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2682    COPY_NODE(opline->op1, foreach_copy->result);
2683    SET_UNUSED(opline->op2);
2684    opline->extended_value = 1;
2685
2686    if (foreach_copy->op1_type != IS_UNUSED) {
2687        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2688
2689        opline->opcode = (foreach_copy->op1_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2690        COPY_NODE(opline->op1, foreach_copy->op1);
2691        SET_UNUSED(opline->op2);
2692        opline->extended_value = 0;
2693    }
2694
2695    return 0;
2696}
2697/* }}} */
2698
2699void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
2700{
2701    zend_op *opline;
2702    int start_op_number, end_op_number;
2703    zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2704
2705    /* The error for use of return inside a generator is thrown in pass_two. */
2706
2707    if (do_end_vparse) {
2708        if (returns_reference && !zend_is_function_or_method_call(expr)) {
2709            zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
2710        } else {
2711            zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);
2712        }
2713    }
2714
2715    start_op_number = get_next_op_number(CG(active_op_array));
2716
2717#ifdef ZTS
2718    zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC);
2719    zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC);
2720#else
2721    zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr);
2722    zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
2723#endif
2724
2725    end_op_number = get_next_op_number(CG(active_op_array));
2726    while (start_op_number < end_op_number) {
2727        CG(active_op_array)->opcodes[start_op_number].extended_value |= EXT_TYPE_FREE_ON_RETURN;
2728        start_op_number++;
2729    }
2730
2731    if (CG(context).in_finally) {
2732        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2733        opline->opcode = ZEND_DISCARD_EXCEPTION;
2734        SET_UNUSED(opline->op1);
2735        SET_UNUSED(opline->op2);
2736    }
2737
2738    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2739
2740    opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
2741
2742    if (expr) {
2743        SET_NODE(opline->op1, expr);
2744
2745        if (do_end_vparse && zend_is_function_or_method_call(expr)) {
2746            opline->extended_value = ZEND_RETURNS_FUNCTION;
2747        }
2748    } else {
2749        opline->op1_type = IS_CONST;
2750        LITERAL_NULL(opline->op1);
2751    }
2752
2753    SET_UNUSED(opline->op2);
2754}
2755/* }}} */
2756
2757void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC) /* {{{ */
2758{
2759    zend_op *opline;
2760
2761    if (!CG(active_op_array)->function_name) {
2762        zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
2763    }
2764
2765    CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
2766
2767    if (is_variable) {
2768        if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(value)) {
2769            zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
2770        } else {
2771            zend_do_end_variable_parse(value, BP_VAR_R, 0 TSRMLS_CC);
2772        }
2773    }
2774
2775    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2776
2777    opline->opcode = ZEND_YIELD;
2778
2779    if (value) {
2780        SET_NODE(opline->op1, value);
2781
2782        if (is_variable && zend_is_function_or_method_call(value)) {
2783            opline->extended_value = ZEND_RETURNS_FUNCTION;
2784        }
2785    } else {
2786        SET_UNUSED(opline->op1);
2787    }
2788
2789    if (key) {
2790        SET_NODE(opline->op2, key);
2791    } else {
2792        SET_UNUSED(opline->op2);
2793    }
2794
2795    opline->result_type = IS_TMP_VAR;
2796    opline->result.var = get_temporary_variable(CG(active_op_array));
2797    GET_NODE(result, opline->result);
2798}
2799/* }}} */
2800
2801static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
2802{
2803    int try_catch_offset = CG(active_op_array)->last_try_catch++;
2804
2805    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);
2806    CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
2807    CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0;
2808    CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
2809    CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
2810    return try_catch_offset;
2811}
2812/* }}} */
2813
2814static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC) /* {{{ */
2815{
2816    CG(active_op_array)->try_catch_array[offset].catch_op = catch_op;
2817}
2818/* }}} */
2819
2820void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */
2821{
2822    open_parentheses->u.op.opline_num = get_next_op_number(CG(active_op_array));
2823}
2824/* }}} */
2825
2826void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */
2827{
2828    int jmp_op_number = get_next_op_number(CG(active_op_array));
2829    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2830    zend_llist jmp_list;
2831    zend_llist *jmp_list_ptr;
2832
2833    opline->opcode = ZEND_JMP;
2834    SET_UNUSED(opline->op1);
2835    SET_UNUSED(opline->op2);
2836    /* save for backpatching */
2837
2838    zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
2839    zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
2840    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2841    zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2842
2843    catch_token->EA = get_next_op_number(CG(active_op_array));
2844}
2845/* }}} */
2846
2847void zend_do_mark_last_catch(const znode *first_catch, const znode *last_additional_catch TSRMLS_DC) /* {{{ */
2848{
2849    CG(active_op_array)->last--;
2850    zend_do_if_end(TSRMLS_C);
2851    if (last_additional_catch->u.op.opline_num == -1) {
2852        CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1;
2853        CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2854    } else {
2855        CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].result.num = 1;
2856        CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2857    }
2858    DEC_BPC(CG(active_op_array));
2859}
2860/* }}} */
2861
2862void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */
2863{
2864    try_token->u.op.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC);
2865    INC_BPC(CG(active_op_array));
2866}
2867/* }}} */
2868
2869void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */
2870{
2871    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2872
2873    finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
2874    /* call the the "finally" block */
2875    opline->opcode = ZEND_FAST_CALL;
2876    SET_UNUSED(opline->op1);
2877    opline->op1.opline_num = finally_token->u.op.opline_num + 1;
2878    SET_UNUSED(opline->op2);
2879    /* jump to code after the "finally" block,
2880     * the actual jump address is going to be set in zend_do_end_finally()
2881     */
2882    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2883    opline->opcode = ZEND_JMP;
2884    SET_UNUSED(opline->op1);
2885    SET_UNUSED(opline->op2);
2886
2887    CG(context).in_finally++;
2888}
2889/* }}} */
2890
2891void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
2892{
2893    long catch_op_number;
2894    zend_op *opline;
2895    znode catch_class;
2896
2897    if (class_name->op_type == IS_CONST &&
2898        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2899        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2900        catch_class = *class_name;
2901    } else {
2902        zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
2903    }
2904
2905    catch_op_number = get_next_op_number(CG(active_op_array));
2906    if (first_catch) {
2907        first_catch->u.op.opline_num = catch_op_number;
2908    }
2909
2910    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2911    opline->opcode = ZEND_CATCH;
2912    opline->op1_type = IS_CONST;
2913    opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC);
2914    opline->op2_type = IS_CV;
2915    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);
2916    Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
2917    opline->result.num = 0; /* 1 means it's the last catch in the block */
2918
2919    catch_token->u.op.opline_num = catch_op_number;
2920}
2921/* }}} */
2922
2923void zend_do_end_catch(znode *catch_token TSRMLS_DC) /* {{{ */
2924{
2925    int jmp_op_number = get_next_op_number(CG(active_op_array));
2926    zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2927    zend_llist *jmp_list_ptr;
2928
2929    opline->opcode = ZEND_JMP;
2930    SET_UNUSED(opline->op1);
2931    SET_UNUSED(opline->op2);
2932    /* save for backpatching */
2933
2934    zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2935    zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2936
2937    CG(active_op_array)->opcodes[catch_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2938}
2939/* }}} */
2940
2941void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ */ {
2942    if (catch_token->op_type != IS_UNUSED) {
2943        zend_add_catch_element(try_token->u.op.opline_num, catch_token->EA TSRMLS_CC);
2944    }
2945}
2946/* }}} */
2947
2948void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */
2949{
2950    if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
2951        zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
2952    }
2953    if (finally_token->op_type != IS_UNUSED) {
2954        zend_op *opline;
2955
2956        CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
2957        CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
2958        CG(active_op_array)->has_finally_block = 1;
2959
2960        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2961        opline->opcode = ZEND_FAST_RET;
2962        SET_UNUSED(opline->op1);
2963        SET_UNUSED(opline->op2);
2964
2965        CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
2966
2967        CG(context).in_finally--;
2968    }
2969}
2970/* }}} */
2971
2972void zend_do_throw(const znode *expr TSRMLS_DC) /* {{{ */
2973{
2974    zend_op *opline;
2975
2976    opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2977    opline->opcode = ZEND_THROW;
2978    SET_NODE(opline->op1, expr);
2979    SET_UNUSED(opline->op2);
2980}
2981/* }}} */
2982
2983ZEND_API void function_add_ref(zend_function *function) /* {{{ */
2984{
2985    if (function->type == ZEND_USER_FUNCTION) {
2986        zend_op_array *op_array = &function->op_array;
2987
2988        (*op_array->refcount)++;
2989        if (op_array->static_variables) {
2990            HashTable *static_variables = op_array->static_variables;
2991            zval *tmp_zval;
2992
2993            ALLOC_HASHTABLE(op_array->static_variables);
2994            zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
2995            zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *));
2996        }
2997        op_array->run_time_cache = NULL;
2998    }
2999}
3000/* }}} */
3001
3002static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
3003{
3004    zend_function *function, *new_function;
3005
3006    if (!ce->parent) {
3007        return;
3008    }
3009
3010    /* You cannot change create_object */
3011    ce->create_object = ce->parent->create_object;
3012
3013    /* Inherit special functions if needed */
3014    if (!ce->get_iterator) {
3015        ce->get_iterator = ce->parent->get_iterator;
3016    }
3017    if (!ce->iterator_funcs.funcs) {
3018        ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
3019    }
3020    if (!ce->__get) {
3021        ce->__get   = ce->parent->__get;
3022    }
3023    if (!ce->__set) {
3024        ce->__set = ce->parent->__set;
3025    }
3026    if (!ce->__unset) {
3027        ce->__unset = ce->parent->__unset;
3028    }
3029    if (!ce->__isset) {
3030        ce->__isset = ce->parent->__isset;
3031    }
3032    if (!ce->__call) {
3033        ce->__call = ce->parent->__call;
3034    }
3035    if (!ce->__callstatic) {
3036        ce->__callstatic = ce->parent->__callstatic;
3037    }
3038    if (!ce->__tostring) {
3039        ce->__tostring = ce->parent->__tostring;
3040    }
3041    if (!ce->clone) {
3042        ce->clone = ce->parent->clone;
3043    }
3044    if(!ce->serialize) {
3045        ce->serialize = ce->parent->serialize;
3046    }
3047    if(!ce->unserialize) {
3048        ce->unserialize = ce->parent->unserialize;
3049    }
3050    if (!ce->destructor) {
3051        ce->destructor   = ce->parent->destructor;
3052    }
3053    if (ce->constructor) {
3054        if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
3055            zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
3056                ce->parent->name, ce->parent->constructor->common.function_name,
3057                ce->name, ce->constructor->common.function_name
3058                );
3059        }
3060        return;
3061    }
3062
3063    if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) {
3064        /* inherit parent's constructor */
3065        zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function);
3066        function_add_ref(new_function);
3067    } else {
3068        /* Don't inherit the old style constructor if we already have the new style constructor */
3069        char *lc_class_name;
3070        char *lc_parent_class_name;
3071
3072        lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
3073        if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
3074            lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
3075            if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
3076                    zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
3077                if (function->common.fn_flags & ZEND_ACC_CTOR) {
3078                    /* inherit parent's constructor */
3079                    zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function);
3080                    function_add_ref(new_function);
3081                }
3082            }
3083            efree(lc_parent_class_name);
3084        }
3085        efree(lc_class_name);
3086    }
3087    ce->constructor = ce->parent->constructor;
3088}
3089/* }}} */
3090
3091char *zend_visibility_string(zend_uint fn_flags) /* {{{ */
3092{
3093    if (fn_flags & ZEND_ACC_PRIVATE) {
3094        return "private";
3095    }
3096    if (fn_flags & ZEND_ACC_PROTECTED) {
3097        return "protected";
3098    }
3099    if (fn_flags & ZEND_ACC_PUBLIC) {
3100        return "public";
3101    }
3102    return "";
3103}
3104/* }}} */
3105
3106static void do_inherit_method(zend_function *function) /* {{{ */
3107{
3108    /* The class entry of the derived function intentionally remains the same
3109     * as that of the parent class.  That allows us to know in which context
3110     * we're running, and handle private method calls properly.
3111     */
3112    function_add_ref(function);
3113}
3114/* }}} */
3115
3116static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
3117{
3118    zend_uint i;
3119
3120    /* If it's a user function then arg_info == NULL means we don't have any parameters but
3121     * we still need to do the arg number checks.  We are only willing to ignore this for internal
3122     * functions because extensions don't always define arg_info.
3123     */
3124    if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
3125        return 1;
3126    }
3127
3128    /* Checks for constructors only if they are declared in an interface,
3129     * or explicitly marked as abstract
3130     */
3131    if ((fe->common.fn_flags & ZEND_ACC_CTOR)
3132        && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3133            && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
3134        return 1;
3135    }
3136
3137    /* If both methods are private do not enforce a signature */
3138    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
3139        return 1;
3140    }
3141
3142    /* check number of arguments */
3143    if (proto->common.required_num_args < fe->common.required_num_args
3144        || proto->common.num_args > fe->common.num_args) {
3145        return 0;
3146    }
3147
3148    if (fe->common.type != ZEND_USER_FUNCTION
3149        && (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0
3150        && (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) {
3151        return 0;
3152    }
3153
3154    /* by-ref constraints on return values are covariant */
3155    if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
3156        && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
3157        return 0;
3158    }
3159
3160    for (i=0; i < proto->common.num_args; i++) {
3161        if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) {
3162            /* Only one has a type hint and the other one doesn't */
3163            return 0;
3164        }
3165
3166        if (fe->common.arg_info[i].class_name) {
3167            const char *fe_class_name, *proto_class_name;
3168            zend_uint fe_class_name_len, proto_class_name_len;
3169
3170            if (!strcasecmp(fe->common.arg_info[i].class_name, "parent") && proto->common.scope) {
3171                fe_class_name = proto->common.scope->name;
3172                fe_class_name_len = proto->common.scope->name_length;
3173            } else if (!strcasecmp(fe->common.arg_info[i].class_name, "self") && fe->common.scope) {
3174                fe_class_name = fe->common.scope->name;
3175                fe_class_name_len = fe->common.scope->name_length;
3176            } else {
3177                fe_class_name = fe->common.arg_info[i].class_name;
3178                fe_class_name_len = fe->common.arg_info[i].class_name_len;
3179            }
3180
3181            if (!strcasecmp(proto->common.arg_info[i].class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
3182                proto_class_name = proto->common.scope->parent->name;
3183                proto_class_name_len = proto->common.scope->parent->name_length;
3184            } else if (!strcasecmp(proto->common.arg_info[i].class_name, "self") && proto->common.scope) {
3185                proto_class_name = proto->common.scope->name;
3186                proto_class_name_len = proto->common.scope->name_length;
3187            } else {
3188                proto_class_name = proto->common.arg_info[i].class_name;
3189                proto_class_name_len = proto->common.arg_info[i].class_name_len;
3190            }
3191
3192            if (strcasecmp(fe_class_name, proto_class_name)!=0) {
3193                const char *colon;
3194
3195                if (fe->common.type != ZEND_USER_FUNCTION) {
3196                    return 0;
3197                } else if (strchr(proto_class_name, '\\') != NULL ||
3198                        (colon = zend_memrchr(fe_class_name, '\\', fe_class_name_len)) == NULL ||
3199                        strcasecmp(colon+1, proto_class_name) != 0) {
3200                    zend_class_entry **fe_ce, **proto_ce;
3201                    int found, found2;
3202
3203                    found = zend_lookup_class(fe_class_name, fe_class_name_len, &fe_ce TSRMLS_CC);
3204                    found2 = zend_lookup_class(proto_class_name, proto_class_name_len, &proto_ce TSRMLS_CC);
3205
3206                    /* Check for class alias */
3207                    if (found != SUCCESS || found2 != SUCCESS ||
3208                            (*fe_ce)->type == ZEND_INTERNAL_CLASS ||
3209                            (*proto_ce)->type == ZEND_INTERNAL_CLASS ||
3210                            *fe_ce != *proto_ce) {
3211                        return 0;
3212                    }
3213                }
3214            }
3215        }
3216        if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
3217            /* Incompatible type hint */
3218            return 0;
3219        }
3220
3221        /* by-ref constraints on arguments are invariant */
3222        if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
3223            return 0;
3224        }
3225    }
3226
3227    if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) {
3228        for (i=proto->common.num_args; i < fe->common.num_args; i++) {
3229            if (!fe->common.arg_info[i].pass_by_reference) {
3230                return 0;
3231            }
3232        }
3233    }
3234    return 1;
3235}
3236/* }}} */
3237
3238#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
3239    if (UNEXPECTED(offset - buf + size >= length)) {    \
3240        length += size + 1;                 \
3241        buf = erealloc(buf, length);        \
3242    }
3243
3244static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
3245{
3246    char *offset, *buf;
3247    zend_uint length = 1024;
3248
3249    offset = buf = (char *)emalloc(length * sizeof(char));
3250    if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3251        *(offset++) = '&';
3252        *(offset++) = ' ';
3253    }
3254
3255    if (fptr->common.scope) {
3256        memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length);
3257        offset += fptr->common.scope->name_length;
3258        *(offset++) = ':';
3259        *(offset++) = ':';
3260    }
3261
3262    {
3263        size_t name_len = strlen(fptr->common.function_name);
3264        REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
3265        memcpy(offset, fptr->common.function_name, name_len);
3266        offset += name_len;
3267    }
3268
3269    *(offset++) = '(';
3270    if (fptr->common.arg_info) {
3271        zend_uint i, required;
3272        zend_arg_info *arg_info = fptr->common.arg_info;
3273
3274        required = fptr->common.required_num_args;
3275        for (i = 0; i < fptr->common.num_args;) {
3276            if (arg_info->class_name) {
3277                const char *class_name;
3278                zend_uint class_name_len;
3279                if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
3280                    class_name = fptr->common.scope->name;
3281                    class_name_len = fptr->common.scope->name_length;
3282                } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
3283                    class_name = fptr->common.scope->parent->name;
3284                    class_name_len = fptr->common.scope->parent->name_length;
3285                } else {
3286                    class_name = arg_info->class_name;
3287                    class_name_len = arg_info->class_name_len;
3288                }
3289                REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
3290                memcpy(offset, class_name, class_name_len);
3291                offset += class_name_len;
3292                *(offset++) = ' ';
3293            } else if (arg_info->type_hint) {
3294                zend_uint type_name_len;
3295                char *type_name = zend_get_type_by_const(arg_info->type_hint);
3296                type_name_len = strlen(type_name);
3297                REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
3298                memcpy(offset, type_name, type_name_len);
3299                offset += type_name_len;
3300                *(offset++) = ' ';
3301            }
3302
3303            if (arg_info->pass_by_reference) {
3304                *(offset++) = '&';
3305            }
3306            *(offset++) = '$';
3307
3308            if (arg_info->name) {
3309                REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
3310                memcpy(offset, arg_info->name, arg_info->name_len);
3311                offset += arg_info->name_len;
3312            } else {
3313                zend_uint idx = i;
3314                memcpy(offset, "param", 5);
3315                offset += 5;
3316                do {
3317                    *(offset++) = (char) (idx % 10) + '0';
3318                    idx /= 10;
3319                } while (idx > 0);
3320            }
3321            if (i >= required) {
3322                *(offset++) = ' ';
3323                *(offset++) = '=';
3324                *(offset++) = ' ';
3325                if (fptr->type == ZEND_USER_FUNCTION) {
3326                    zend_op *precv = NULL;
3327                    {
3328                        zend_uint idx  = i;
3329                        zend_op *op = ((zend_op_array *)fptr)->opcodes;
3330                        zend_op *end = op + ((zend_op_array *)fptr)->last;
3331
3332                        ++idx;
3333                        while (op < end) {
3334                            if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
3335                                    && op->op1.num == (long)idx)
3336                            {
3337                                precv = op;
3338                            }
3339                            ++op;
3340                        }
3341                    }
3342                    if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
3343                        zval *zv, zv_copy;
3344                        int use_copy;
3345                        ALLOC_ZVAL(zv);
3346                        *zv = *precv->op2.zv;
3347                        zval_copy_ctor(zv);
3348                        INIT_PZVAL(zv);
3349                        zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
3350                        if (Z_TYPE_P(zv) == IS_BOOL) {
3351                            if (Z_LVAL_P(zv)) {
3352                                memcpy(offset, "true", 4);
3353                                offset += 4;
3354                            } else {
3355                                memcpy(offset, "false", 5);
3356                                offset += 5;
3357                            }
3358                        } else if (Z_TYPE_P(zv) == IS_NULL) {
3359                            memcpy(offset, "NULL", 4);
3360                            offset += 4;
3361                        } else if (Z_TYPE_P(zv) == IS_STRING) {
3362                            *(offset++) = '\'';
3363                            REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
3364                            memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
3365                            offset += MIN(Z_STRLEN_P(zv), 10);
3366                            if (Z_STRLEN_P(zv) > 10) {
3367                                *(offset++) = '.';
3368                                *(offset++) = '.';
3369                                *(offset++) = '.';
3370                            }
3371                            *(offset++) = '\'';
3372                        } else if (Z_TYPE_P(zv) == IS_ARRAY) {
3373                            memcpy(offset, "Array", 5);
3374                            offset += 5;
3375                        } else {
3376                            zend_make_printable_zval(zv, &zv_copy, &use_copy);
3377                            REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN(zv_copy));
3378                            memcpy(offset, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
3379                            offset += Z_STRLEN(zv_copy);
3380                            if (use_copy) {
3381                                zval_dtor(&zv_copy);
3382                            }
3383                        }
3384                        zval_ptr_dtor(&zv);
3385                    }
3386                } else {
3387                    memcpy(offset, "NULL", 4);
3388                    offset += 4;
3389                }
3390            }
3391
3392            if (++i < fptr->common.num_args) {
3393                *(offset++) = ',';
3394                *(offset++) = ' ';
3395            }
3396            arg_info++;
3397            REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
3398        }
3399    }
3400    *(offset++) = ')';
3401    *offset = '\0';
3402
3403    return buf;
3404}
3405/* }}} */
3406
3407static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
3408{
3409    zend_uint child_flags;
3410    zend_uint parent_flags = parent->common.fn_flags;
3411
3412    if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3413        && parent->common.fn_flags & ZEND_ACC_ABSTRACT
3414        && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
3415        && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
3416        zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
3417            parent->common.scope->name,
3418            child->common.function_name,
3419            child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);
3420    }
3421
3422    if (parent_flags & ZEND_ACC_FINAL) {
3423        zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name);
3424    }
3425
3426    child_flags = child->common.fn_flags;
3427    /* You cannot change from static to non static and vice versa.
3428     */
3429    if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
3430        if (child->common.fn_flags & ZEND_ACC_STATIC) {
3431            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));
3432        } else {
3433            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));
3434        }
3435    }
3436
3437    /* Disallow making an inherited method abstract. */
3438    if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
3439        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));
3440    }
3441
3442    if (parent_flags & ZEND_ACC_CHANGED) {
3443        child->common.fn_flags |= ZEND_ACC_CHANGED;
3444    } else {
3445        /* Prevent derived classes from restricting access that was available in parent classes
3446         */
3447        if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
3448            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");
3449        } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
3450            && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
3451            child->common.fn_flags |= ZEND_ACC_CHANGED;
3452        }
3453    }
3454
3455    if (parent_flags & ZEND_ACC_PRIVATE) {
3456        child->common.prototype = NULL;
3457    } else if (parent_flags & ZEND_ACC_ABSTRACT) {
3458        child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
3459        child->common.prototype = parent;
3460    } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
3461        /* ctors only have a prototype if it comes from an interface */
3462        child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
3463    }
3464
3465    if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3466        if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
3467            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? child->common.prototype : parent TSRMLS_CC));
3468        }
3469    } 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 */
3470        if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
3471            char *method_prototype = zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC);
3472            zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
3473            efree(method_prototype);
3474        }
3475    }
3476}
3477/* }}} */
3478
3479static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, const zend_hash_key *hash_key, zend_class_entry *child_ce) /* {{{ */
3480{
3481    zend_uint parent_flags = parent->common.fn_flags;
3482    zend_function *child;
3483    TSRMLS_FETCH();
3484
3485    if (zend_hash_quick_find(child_function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) {
3486        if (parent_flags & (ZEND_ACC_ABSTRACT)) {
3487            child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3488        }
3489        return 1; /* method doesn't exist in child, copy from parent */
3490    }
3491
3492    do_inheritance_check_on_method(child, parent TSRMLS_CC);
3493
3494    return 0;
3495}
3496/* }}} */
3497
3498static 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) /* {{{ */
3499{
3500    zend_property_info *child_info;
3501    zend_class_entry *parent_ce = ce->parent;
3502
3503    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
3504        if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3505            child_info->flags |= ZEND_ACC_CHANGED;
3506        } else {
3507            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);
3508            if(ce->type & ZEND_INTERNAL_CLASS) {
3509                zend_duplicate_property_info_internal(child_info);
3510            } else {
3511                zend_duplicate_property_info(child_info);
3512            }
3513            child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
3514            child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
3515        }
3516        return 0; /* don't copy access information to child */
3517    }
3518
3519    if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3520        if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
3521            zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
3522                (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,
3523                (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
3524
3525        }
3526
3527        if(parent_info->flags & ZEND_ACC_CHANGED) {
3528            child_info->flags |= ZEND_ACC_CHANGED;
3529        }
3530
3531        if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
3532            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");
3533        } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
3534            zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
3535            ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
3536            ce->default_properties_table[child_info->offset] = NULL;
3537            child_info->offset = parent_info->offset;
3538        }
3539        return 0;   /* Don't copy from parent */
3540    } else {
3541        return 1;   /* Copy from parent */
3542    }
3543}
3544/* }}} */
3545
3546static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3547{
3548    if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
3549        zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name);
3550    }
3551    if (ce == iface) {
3552        zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name);
3553    }
3554}
3555/* }}} */
3556
3557ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
3558{
3559    /* expects interface to be contained in ce's interface list already */
3560    zend_uint i, ce_num, if_num = iface->num_interfaces;
3561    zend_class_entry *entry;
3562
3563    if (if_num==0) {
3564        return;
3565    }
3566    ce_num = ce->num_interfaces;
3567
3568    if (ce->type == ZEND_INTERNAL_CLASS) {
3569        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3570    } else {
3571        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3572    }
3573
3574    /* Inherit the interfaces, only if they're not already inherited by the class */
3575    while (if_num--) {
3576        entry = iface->interfaces[if_num];
3577        for (i = 0; i < ce_num; i++) {
3578            if (ce->interfaces[i] == entry) {
3579                break;
3580            }
3581        }
3582        if (i == ce_num) {
3583            ce->interfaces[ce->num_interfaces++] = entry;
3584        }
3585    }
3586
3587    /* and now call the implementing handlers */
3588    while (ce_num < ce->num_interfaces) {
3589        do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
3590    }
3591}
3592/* }}} */
3593
3594#ifdef ZTS
3595static void zval_internal_ctor(zval **p) /* {{{ */
3596{
3597    zval *orig_ptr = *p;
3598
3599    ALLOC_ZVAL(*p);
3600    MAKE_COPY_ZVAL(&orig_ptr, *p);
3601}
3602/* }}} */
3603
3604# define zval_property_ctor(parent_ce, ce) \
3605    ((void (*)(void *)) (((parent_ce)->type != (ce)->type) ? zval_internal_ctor : zval_add_ref))
3606#else
3607# define zval_property_ctor(parent_ce, ce) \
3608    ((void (*)(void *)) zval_add_ref)
3609#endif
3610
3611ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
3612{
3613    zend_property_info *property_info;
3614
3615    if ((ce->ce_flags & ZEND_ACC_INTERFACE)
3616        && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
3617        zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
3618    }
3619    if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
3620        zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name);
3621    }
3622
3623    ce->parent = parent_ce;
3624    /* Copy serialize/unserialize callbacks */
3625    if (!ce->serialize) {
3626        ce->serialize   = parent_ce->serialize;
3627    }
3628    if (!ce->unserialize) {
3629        ce->unserialize = parent_ce->unserialize;
3630    }
3631
3632    /* Inherit interfaces */
3633    zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
3634
3635    /* Inherit properties */
3636    if (parent_ce->default_properties_count) {
3637        int i = ce->default_properties_count + parent_ce->default_properties_count;
3638
3639        ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3640        if (ce->default_properties_count) {
3641            while (i-- > parent_ce->default_properties_count) {
3642                ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
3643            }
3644        }
3645        for (i = 0; i < parent_ce->default_properties_count; i++) {
3646            ce->default_properties_table[i] = parent_ce->default_properties_table[i];
3647            if (ce->default_properties_table[i]) {
3648#ifdef ZTS
3649                if (parent_ce->type != ce->type) {
3650                    zval *p;
3651
3652                    ALLOC_ZVAL(p);
3653                    MAKE_COPY_ZVAL(&ce->default_properties_table[i], p);
3654                    ce->default_properties_table[i] = p;
3655                } else {
3656                    Z_ADDREF_P(ce->default_properties_table[i]);
3657                }
3658#else
3659                Z_ADDREF_P(ce->default_properties_table[i]);
3660#endif
3661            }
3662        }
3663        ce->default_properties_count += parent_ce->default_properties_count;
3664    }
3665
3666    if (parent_ce->type != ce->type) {
3667        /* User class extends internal class */
3668        zend_update_class_constants(parent_ce  TSRMLS_CC);
3669        if (parent_ce->default_static_members_count) {
3670            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3671
3672            ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i);
3673            if (ce->default_static_members_count) {
3674                while (i-- > parent_ce->default_static_members_count) {
3675                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3676                }
3677            }
3678            for (i = 0; i < parent_ce->default_static_members_count; i++) {
3679                SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
3680                ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
3681                Z_ADDREF_P(ce->default_static_members_table[i]);
3682            }
3683            ce->default_static_members_count += parent_ce->default_static_members_count;
3684            ce->static_members_table = ce->default_static_members_table;
3685        }
3686    } else {
3687        if (parent_ce->default_static_members_count) {
3688            int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3689
3690            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3691            if (ce->default_static_members_count) {
3692                while (i-- > parent_ce->default_static_members_count) {
3693                    ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3694                }
3695            }
3696            for (i = 0; i < parent_ce->default_static_members_count; i++) {
3697                SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]);
3698                ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
3699                Z_ADDREF_P(ce->default_static_members_table[i]);
3700            }
3701            ce->default_static_members_count += parent_ce->default_static_members_count;
3702            if (ce->type == ZEND_USER_CLASS) {
3703                ce->static_members_table = ce->default_static_members_table;
3704            }
3705        }
3706    }
3707
3708    for (zend_hash_internal_pointer_reset(&ce->properties_info);
3709    zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS;
3710    zend_hash_move_forward(&ce->properties_info)) {
3711        if (property_info->ce == ce) {
3712            if (property_info->flags & ZEND_ACC_STATIC) {
3713                property_info->offset += parent_ce->default_static_members_count;
3714            } else {
3715                property_info->offset += parent_ce->default_properties_count;
3716            }
3717        }
3718    }
3719
3720    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);
3721
3722    zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, zval_property_ctor(parent_ce, ce), NULL, sizeof(zval *), 0);
3723    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);
3724    do_inherit_parent_constructor(ce);
3725
3726    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
3727        ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
3728    } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
3729        /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
3730        zend_verify_abstract_class(ce TSRMLS_CC);
3731    }
3732    ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
3733}
3734/* }}} */
3735
3736static 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) /* {{{ */
3737{
3738    zval **old_constant;
3739
3740    if (zend_hash_quick_find(child_constants_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**)&old_constant) == SUCCESS) {
3741        if (*old_constant != *parent_constant) {
3742            zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", hash_key->arKey, iface->name);
3743        }
3744        return 0;
3745    }
3746    return 1;
3747}
3748/* }}} */
3749
3750static int do_interface_constant_check(zval **val TSRMLS_DC, int num_args, va_list args, const zend_hash_key *key) /* {{{ */
3751{
3752    zend_class_entry **iface = va_arg(args, zend_class_entry**);
3753
3754    do_inherit_constant_check(&(*iface)->constants_table, (const zval **) val, key, *iface);
3755
3756    return ZEND_HASH_APPLY_KEEP;
3757}
3758/* }}} */
3759
3760ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3761{
3762    zend_uint i, ignore = 0;
3763    zend_uint current_iface_num = ce->num_interfaces;
3764    zend_uint parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
3765
3766    for (i = 0; i < ce->num_interfaces; i++) {
3767        if (ce->interfaces[i] == NULL) {
3768            memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
3769            i--;
3770        } else if (ce->interfaces[i] == iface) {
3771            if (i < parent_iface_num) {
3772                ignore = 1;
3773            } else {
3774                zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name);
3775            }
3776        }
3777    }
3778    if (ignore) {
3779        /* Check for attempt to redeclare interface constants */
3780        zend_hash_apply_with_arguments(&ce->constants_table TSRMLS_CC, (apply_func_args_t) do_interface_constant_check, 1, &iface);
3781    } else {
3782        if (ce->num_interfaces >= current_iface_num) {
3783            if (ce->type == ZEND_INTERNAL_CLASS) {
3784                ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3785            } else {
3786                ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3787            }
3788        }
3789        ce->interfaces[ce->num_interfaces++] = iface;
3790
3791        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);
3792        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);
3793
3794        do_implement_interface(ce, iface TSRMLS_CC);
3795        zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
3796    }
3797}
3798/* }}} */
3799
3800ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
3801{
3802    zend_uint i, ignore = 0;
3803    zend_uint current_trait_num = ce->num_traits;
3804    zend_uint parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
3805
3806    for (i = 0; i < ce->num_traits; i++) {
3807        if (ce->traits[i] == NULL) {
3808            memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
3809            i--;
3810        } else if (ce->traits[i] == trait) {
3811            if (i < parent_trait_num) {
3812                ignore = 1;
3813            }
3814        }
3815    }
3816    if (!ignore) {
3817        if (ce->num_traits >= current_trait_num) {
3818            if (ce->type == ZEND_INTERNAL_CLASS) {
3819                ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3820            } else {
3821                ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3822            }
3823        }
3824        ce->traits[ce->num_traits++] = trait;
3825    }
3826}
3827/* }}} */
3828
3829static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
3830{
3831    zend_uint    fn_flags = fn->common.scope->ce_flags;
3832    zend_uint other_flags = other_fn->common.scope->ce_flags;
3833
3834    return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
3835        && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
3836        && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
3837            (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
3838}
3839/* }}} */
3840
3841static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */
3842{
3843    if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {
3844        ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
3845    } else if (!strncmp(mname, ZEND_CONSTRUCTOR_FUNC_NAME, mname_len)) {
3846        if (ce->constructor) {
3847            zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3848        }
3849        ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
3850    } else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME,  mname_len)) {
3851        ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
3852    } else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) {
3853        ce->__get = fe;
3854    } else if (!strncmp(mname, ZEND_SET_FUNC_NAME, mname_len)) {
3855        ce->__set = fe;
3856    } else if (!strncmp(mname, ZEND_CALL_FUNC_NAME, mname_len)) {
3857        ce->__call = fe;
3858    } else if (!strncmp(mname, ZEND_UNSET_FUNC_NAME, mname_len)) {
3859        ce->__unset = fe;
3860    } else if (!strncmp(mname, ZEND_ISSET_FUNC_NAME, mname_len)) {
3861        ce->__isset = fe;
3862    } else if (!strncmp(mname, ZEND_CALLSTATIC_FUNC_NAME, mname_len)) {
3863        ce->__callstatic = fe;
3864    } else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) {
3865        ce->__tostring = fe;
3866    } else if (ce->name_length + 1 == mname_len) {
3867        char *lowercase_name = emalloc(ce->name_length + 1);
3868        zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length);
3869        lowercase_name = (char*)zend_new_interned_string(lowercase_name, ce->name_length + 1, 1 TSRMLS_CC);
3870        if (!memcmp(mname, lowercase_name, mname_len)) {
3871            if (ce->constructor) {
3872                zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3873            }
3874            ce->constructor = fe;
3875            fe->common.fn_flags |= ZEND_ACC_CTOR;
3876        }
3877        str_efree(lowercase_name);
3878    }
3879}
3880/* }}} */
3881
3882static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
3883{
3884    zend_function *existing_fn = NULL;
3885    ulong h = zend_hash_func(arKey, nKeyLength);
3886
3887    if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3888        if (existing_fn->common.scope == ce) {
3889            /* members from the current class override trait methods */
3890            /* use temporary *overriden HashTable to detect hidden conflict */
3891            if (*overriden) {
3892                if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3893                    if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3894                        /* Make sure the trait method is compatible with previosly declared abstract method */
3895                        if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3896                            zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3897                                zend_get_function_declaration(fn TSRMLS_CC),
3898                                zend_get_function_declaration(existing_fn TSRMLS_CC));
3899                        }
3900                    } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3901                        /* Make sure the abstract declaration is compatible with previous declaration */
3902                        if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3903                            zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3904                                zend_get_function_declaration(fn TSRMLS_CC),
3905                                zend_get_function_declaration(existing_fn TSRMLS_CC));
3906                        }
3907                        return;
3908                    }
3909                }
3910            } else {
3911                ALLOC_HASHTABLE(*overriden);
3912                zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
3913            }
3914            zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3915            return;
3916        } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3917            /* Make sure the trait method is compatible with previosly declared abstract method */
3918            if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3919                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3920                    zend_get_function_declaration(fn TSRMLS_CC),
3921                    zend_get_function_declaration(existing_fn TSRMLS_CC));
3922            }
3923        } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3924            /* Make sure the abstract declaration is compatible with previous declaration */
3925            if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3926                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3927                    zend_get_function_declaration(fn TSRMLS_CC),
3928                    zend_get_function_declaration(existing_fn TSRMLS_CC));
3929            }
3930            return;
3931        } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3932            /* two trais can't define the same non-abstract method */
3933#if 1
3934            zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
3935                name, ce->name);
3936#else       /* TODO: better errot message */
3937            zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
3938                fn->common.scope->name, fn->common.function_name,
3939                ce->name, name,
3940                existing_fn->common.scope->name, existing_fn->common.function_name);
3941#endif
3942        } else {
3943            /* inherited members are overridden by members inserted by traits */
3944            /* check whether the trait method fullfills the inheritance requirements */
3945            do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
3946        }
3947    }
3948
3949    function_add_ref(fn);
3950    zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3951    zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
3952}
3953/* }}} */
3954
3955static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
3956{
3957    if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3958
3959        fn->common.scope = ce;
3960
3961        if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3962            ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3963        }
3964        if (fn->op_array.static_variables) {
3965            ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
3966        }
3967    }
3968    return ZEND_HASH_APPLY_KEEP;
3969}
3970/* }}} */
3971
3972static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
3973{
3974    zend_class_entry  *ce;
3975    HashTable         **overriden;
3976    zend_trait_alias  *alias, **alias_ptr;
3977    HashTable         *exclude_table;
3978    char              *lcname;
3979    unsigned int       fnname_len;
3980    zend_function      fn_copy;
3981    void              *dummy;
3982
3983    ce            = va_arg(args, zend_class_entry*);
3984    overriden     = va_arg(args, HashTable**);
3985    exclude_table = va_arg(args, HashTable*);
3986
3987    fnname_len = hash_key->nKeyLength - 1;
3988
3989    /* apply aliases which are qualified with a class name, there should not be any ambiguity */
3990    if (ce->trait_aliases) {
3991        alias_ptr = ce->trait_aliases;
3992        alias = *alias_ptr;
3993        while (alias) {
3994            /* Scope unset or equal to the function we compare to, and the alias applies to fn */
3995            if (alias->alias != NULL
3996                && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
3997                && alias->trait_method->mname_len == fnname_len
3998                && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) {
3999                fn_copy = *fn;
4000
4001                /* if it is 0, no modifieres has been changed */
4002                if (alias->modifiers) {
4003                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
4004                }
4005
4006                lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
4007                zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_CC);
4008                efree(lcname);
4009
4010                /* Record the trait from which this alias was resolved. */
4011                if (!alias->trait_method->ce) {
4012                    alias->trait_method->ce = fn->common.scope;
4013                }
4014            }
4015            alias_ptr++;
4016            alias = *alias_ptr;
4017        }
4018    }
4019
4020    lcname = hash_key->arKey;
4021
4022    if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
4023        /* is not in hashtable, thus, function is not to be excluded */
4024        fn_copy = *fn;
4025
4026        /* apply aliases which have not alias name, just setting visibility */
4027        if (ce->trait_aliases) {
4028            alias_ptr = ce->trait_aliases;
4029            alias = *alias_ptr;
4030            while (alias) {
4031                /* Scope unset or equal to the function we compare to, and the alias applies to fn */
4032                if (alias->alias == NULL && alias->modifiers != 0
4033                    && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
4034                    && (alias->trait_method->mname_len == fnname_len)
4035                    && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, lcname, fnname_len) == 0)) {
4036
4037                    fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
4038
4039                    /** Record the trait from which this alias was resolved. */
4040                    if (!alias->trait_method->ce) {
4041                        alias->trait_method->ce = fn->common.scope;
4042                    }
4043                }
4044                alias_ptr++;
4045                alias = *alias_ptr;
4046            }
4047        }
4048
4049        zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_CC);
4050    }
4051
4052    return ZEND_HASH_APPLY_KEEP;
4053}
4054/* }}} */
4055
4056static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
4057{
4058    zend_uint i;
4059
4060    if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
4061        zend_error(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name);
4062    }
4063
4064    for (i = 0; i < ce->num_traits; i++) {
4065        if (ce->traits[i] == trait) {
4066            return;
4067        }
4068    }
4069    zend_error(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name, ce->name);
4070}
4071/* }}} */
4072
4073static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4074{
4075    size_t i, j = 0;
4076    zend_trait_precedence *cur_precedence;
4077    zend_trait_method_reference *cur_method_ref;
4078    char *lcname;
4079    zend_bool method_exists;
4080
4081    /* resolve class references */
4082    if (ce->trait_precedences) {
4083        i = 0;
4084        while ((cur_precedence = ce->trait_precedences[i])) {
4085            /** Resolve classes for all precedence operations. */
4086            if (cur_precedence->exclude_from_classes) {
4087                cur_method_ref = cur_precedence->trait_method;
4088                if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len,
4089                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4090                    zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4091                }
4092                zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
4093
4094                /** Ensure that the prefered method is actually available. */
4095                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4096                                              cur_method_ref->mname_len);
4097                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4098                                                 lcname,
4099                                                 cur_method_ref->mname_len + 1);
4100                efree(lcname);
4101                if (!method_exists) {
4102                    zend_error(E_COMPILE_ERROR,
4103                               "A precedence rule was defined for %s::%s but this method does not exist",
4104                               cur_method_ref->ce->name,
4105                               cur_method_ref->method_name);
4106                }
4107
4108                /** With the other traits, we are more permissive.
4109                    We do not give errors for those. This allows to be more
4110                    defensive in such definitions.
4111                    However, we want to make sure that the insteadof declartion
4112                    is consistent in itself.
4113                 */
4114                j = 0;
4115                while (cur_precedence->exclude_from_classes[j]) {
4116                    char* class_name = (char*)cur_precedence->exclude_from_classes[j];
4117                    zend_uint name_length = strlen(class_name);
4118
4119                    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))) {
4120                        zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
4121                    }
4122                    zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
4123
4124                    /* make sure that the trait method is not from a class mentioned in
4125                     exclude_from_classes, for consistency */
4126                    if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
4127                        zend_error(E_COMPILE_ERROR,
4128                                   "Inconsistent insteadof definition. "
4129                                   "The method %s is to be used from %s, but %s is also on the exclude list",
4130                                   cur_method_ref->method_name,
4131                                   cur_precedence->trait_method->ce->name,
4132                                   cur_precedence->trait_method->ce->name);
4133                    }
4134
4135                    efree(class_name);
4136                    j++;
4137                }
4138            }
4139            i++;
4140        }
4141    }
4142
4143    if (ce->trait_aliases) {
4144        i = 0;
4145        while (ce->trait_aliases[i]) {
4146            /** For all aliases with an explicit class name, resolve the class now. */
4147            if (ce->trait_aliases[i]->trait_method->class_name) {
4148                cur_method_ref = ce->trait_aliases[i]->trait_method;
4149                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))) {
4150                    zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4151                }
4152                zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
4153
4154                /** And, ensure that the referenced method is resolvable, too. */
4155                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4156                        cur_method_ref->mname_len);
4157                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4158                        lcname, cur_method_ref->mname_len + 1);
4159                efree(lcname);
4160
4161                if (!method_exists) {
4162                    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);
4163                }
4164            }
4165            i++;
4166        }
4167    }
4168}
4169/* }}} */
4170
4171static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
4172{
4173    size_t i = 0, j;
4174
4175    if (!precedences) {
4176        return;
4177    }
4178    while (precedences[i]) {
4179        if (precedences[i]->exclude_from_classes) {
4180            j = 0;
4181            while (precedences[i]->exclude_from_classes[j]) {
4182                if (precedences[i]->exclude_from_classes[j] == trait) {
4183                    zend_uint lcname_len = precedences[i]->trait_method->mname_len;
4184                    char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len);
4185
4186                    if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) {
4187                        efree(lcname);
4188                        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);
4189                    }
4190                    efree(lcname);
4191                }
4192                ++j;
4193            }
4194        }
4195        ++i;
4196    }
4197}
4198/* }}} */
4199
4200static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4201{
4202    zend_uint i;
4203    HashTable *overriden = NULL;
4204
4205    for (i = 0; i < ce->num_traits; i++) {
4206        if (ce->trait_precedences) {
4207            HashTable exclude_table;
4208
4209            /* TODO: revisit this start size, may be its not optimal */
4210            zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
4211
4212            zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
4213
4214            /* copies functions, applies defined aliasing, and excludes unused trait methods */
4215            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);
4216
4217            zend_hash_destroy(&exclude_table);
4218        } else {
4219            zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
4220        }
4221    }
4222
4223    zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
4224
4225    if (overriden) {
4226        zend_hash_destroy(overriden);
4227        FREE_HASHTABLE(overriden);
4228    }
4229}
4230/* }}} */
4231
4232static 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) /* {{{ */
4233{
4234    size_t i;
4235
4236    if (coliding_ce == ce) {
4237        for (i = 0; i < current_trait; i++) {
4238            if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
4239                return ce->traits[i];
4240            }
4241        }
4242    }
4243
4244    return coliding_ce;
4245}
4246/* }}} */
4247
4248static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4249{
4250    size_t i;
4251    zend_property_info *property_info;
4252    zend_property_info *coliding_prop;
4253    zval compare_result;
4254    const char* prop_name;
4255    int   prop_name_length;
4256    ulong prop_hash;
4257    const char* class_name_unused;
4258    zend_bool not_compatible;
4259    zval* prop_value;
4260    char* doc_comment;
4261    zend_uint flags;
4262
4263    /* In the following steps the properties are inserted into the property table
4264     * for that, a very strict approach is applied:
4265     * - check for compatibility, if not compatible with any property in class -> fatal
4266     * - if compatible, then strict notice
4267     */
4268    for (i = 0; i < ce->num_traits; i++) {
4269        for (zend_hash_internal_pointer_reset(&ce->traits[i]->properties_info);
4270             zend_hash_get_current_data(&ce->traits[i]->properties_info, (void *) &property_info) == SUCCESS;
4271             zend_hash_move_forward(&ce->traits[i]->properties_info)) {
4272            /* first get the unmangeld name if necessary,
4273             * then check whether the property is already there
4274             */
4275            flags = property_info->flags;
4276            if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
4277                prop_hash = property_info->h;
4278                prop_name = property_info->name;
4279                prop_name_length = property_info->name_length;
4280            } else {
4281                /* for private and protected we need to unmangle the names */
4282                zend_unmangle_property_name_ex(property_info->name, property_info->name_length,
4283                                            &class_name_unused, &prop_name, &prop_name_length);
4284                prop_hash = zend_get_hash_value(prop_name, prop_name_length + 1);
4285            }
4286
4287            /* next: check for conflicts with current class */
4288            if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
4289                if (coliding_prop->flags & ZEND_ACC_SHADOW) {
4290                    zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
4291                    flags |= ZEND_ACC_CHANGED;
4292                } else {
4293                    if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
4294                        == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
4295                        /* flags are identical, now the value needs to be checked */
4296                        if (flags & ZEND_ACC_STATIC) {
4297                            not_compatible = (FAILURE == compare_function(&compare_result,
4298                                              ce->default_static_members_table[coliding_prop->offset],
4299                                              ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
4300                                  || (Z_LVAL(compare_result) != 0);
4301                        } else {
4302                            not_compatible = (FAILURE == compare_function(&compare_result,
4303                                              ce->default_properties_table[coliding_prop->offset],
4304                                              ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
4305                                  || (Z_LVAL(compare_result) != 0);
4306                        }
4307                    } else {
4308                        /* the flags are not identical, thus, we assume properties are not compatible */
4309                        not_compatible = 1;
4310                    }
4311
4312                    if (not_compatible) {
4313                        zend_error(E_COMPILE_ERROR,
4314                               "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
4315                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4316                                property_info->ce->name,
4317                                prop_name,
4318                                ce->name);
4319                    } else {
4320                        zend_error(E_STRICT,
4321                               "%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",
4322                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4323                                property_info->ce->name,
4324                                prop_name,
4325                                ce->name);
4326                        continue;
4327                    }
4328                }
4329            }
4330
4331            /* property not found, so lets add it */
4332            if (flags & ZEND_ACC_STATIC) {
4333                prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
4334            } else {
4335                prop_value = ce->traits[i]->default_properties_table[property_info->offset];
4336            }
4337            Z_ADDREF_P(prop_value);
4338
4339            doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
4340            zend_declare_property_ex(ce, prop_name, prop_name_length,
4341                                     prop_value, flags,
4342                                     doc_comment, property_info->doc_comment_len TSRMLS_CC);
4343        }
4344    }
4345}
4346/* }}} */
4347
4348static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4349{
4350    int i = 0;
4351    zend_trait_alias* cur_alias;
4352    char* lc_method_name;
4353
4354    if (ce->trait_aliases) {
4355        while (ce->trait_aliases[i]) {
4356            cur_alias = ce->trait_aliases[i];
4357            /** The trait for this alias has not been resolved, this means, this
4358                alias was not applied. Abort with an error. */
4359            if (!cur_alias->trait_method->ce) {
4360                if (cur_alias->alias) {
4361                    /** Plain old inconsistency/typo/bug */
4362                    zend_error(E_COMPILE_ERROR,
4363                               "An alias (%s) was defined for method %s(), but this method does not exist",
4364                               cur_alias->alias,
4365                               cur_alias->trait_method->method_name);
4366                } else {
4367                    /** Here are two possible cases:
4368                        1) this is an attempt to modifiy the visibility
4369                           of a method introduce as part of another alias.
4370                           Since that seems to violate the DRY principle,
4371                           we check against it and abort.
4372                        2) it is just a plain old inconsitency/typo/bug
4373                           as in the case where alias is set. */
4374
4375                    lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name,
4376                                                          cur_alias->trait_method->mname_len);
4377                    if (zend_hash_exists(&ce->function_table,
4378                                         lc_method_name,
4379                                         cur_alias->trait_method->mname_len+1)) {
4380                        efree(lc_method_name);
4381                        zend_error(E_COMPILE_ERROR,
4382                                   "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
4383                                   cur_alias->trait_method->method_name);
4384                    } else {
4385                        efree(lc_method_name);
4386                        zend_error(E_COMPILE_ERROR,
4387                                   "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
4388                                   cur_alias->trait_method->method_name);
4389
4390                    }
4391                }
4392            }
4393            i++;
4394        }
4395    }
4396}
4397/* }}} */
4398
4399ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4400{
4401
4402    if (ce->num_traits <= 0) {
4403        return;
4404    }
4405
4406    /* complete initialization of trait strutures in ce */
4407    zend_traits_init_trait_structures(ce TSRMLS_CC);
4408
4409    /* first care about all methods to be flattened into the class */
4410    zend_do_traits_method_binding(ce TSRMLS_CC);
4411
4412    /* Aliases which have not been applied indicate typos/bugs. */
4413    zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
4414
4415    /* then flatten the properties into it, to, mostly to notfiy developer about problems */
4416    zend_do_traits_property_binding(ce TSRMLS_CC);
4417
4418    /* verify that all abstract methods from traits have been implemented */
4419    zend_verify_abstract_class(ce TSRMLS_CC);
4420
4421    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
4422    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
4423        ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
4424    }
4425}
4426/* }}} */
4427
4428ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */
4429{
4430    zend_function *function;
4431    zval *op1, *op2;
4432
4433    if (compile_time) {
4434        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4435        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4436    } else {
4437        op1 = opline->op1.zv;
4438        op2 = opline->op2.zv;
4439    }
4440
4441    zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function);
4442    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) {
4443        int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
4444        zend_function *old_function;
4445
4446        if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), (void *) &old_function)==SUCCESS
4447            && old_function->type == ZEND_USER_FUNCTION
4448            && old_function->op_array.last > 0) {
4449            zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
4450                        function->common.function_name,
4451                        old_function->op_array.filename,
4452                        old_function->op_array.opcodes[0].lineno);
4453        } else {
4454            zend_error(error_level, "Cannot redeclare %s()", function->common.function_name);
4455        }
4456        return FAILURE;
4457    } else {
4458        (*function->op_array.refcount)++;
4459        function->op_array.static_variables = NULL; /* NULL out the unbound function */
4460        return SUCCESS;
4461    }
4462}
4463/* }}} */
4464
4465void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
4466{
4467    zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
4468    method_ref->ce = NULL;
4469
4470    /* REM: There should not be a need for copying,
4471       zend_do_begin_class_declaration is also just using that string */
4472    if (class_name) {
4473        zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
4474        method_ref->class_name = Z_STRVAL(class_name->u.constant);
4475        method_ref->cname_len  = Z_STRLEN(class_name->u.constant);
4476    } else {
4477        method_ref->class_name = NULL;
4478        method_ref->cname_len  = 0;
4479    }
4480
4481    method_ref->method_name = Z_STRVAL(method_name->u.constant);
4482    method_ref->mname_len   = Z_STRLEN(method_name->u.constant);
4483
4484    result->u.op.ptr = method_ref;
4485    result->op_type = IS_TMP_VAR;
4486}
4487/* }}} */
4488
4489void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
4490{
4491    zend_class_entry *ce = CG(active_class_entry);
4492    zend_trait_alias *trait_alias;
4493
4494    if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
4495        zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
4496        return;
4497    } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) {
4498        zend_error(E_COMPILE_ERROR, "Cannot use 'abstract' as method modifier");
4499        return;
4500    } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) {
4501        zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier");
4502        return;
4503    }
4504
4505    trait_alias = emalloc(sizeof(zend_trait_alias));
4506    trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4507    trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
4508    if (alias) {
4509        trait_alias->alias = Z_STRVAL(alias->u.constant);
4510        trait_alias->alias_len = Z_STRLEN(alias->u.constant);
4511    } else {
4512        trait_alias->alias = NULL;
4513    }
4514    zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
4515}
4516/* }}} */
4517
4518void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
4519{
4520    zend_class_entry *ce = CG(active_class_entry);
4521    zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
4522
4523    trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4524    trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.op.ptr;
4525
4526    zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
4527}
4528/* }}} */
4529
4530ZEND_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) /* {{{ */
4531{
4532    zend_class_entry *ce, **pce;
4533    zval *op1, *op2;
4534
4535    if (compile_time) {
4536        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4537        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4538    } else {
4539        op1 = opline->op1.zv;
4540        op2 = opline->op2.zv;
4541    }
4542    if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) {
4543        zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
4544        return NULL;
4545    } else {
4546        ce = *pce;
4547    }
4548    ce->refcount++;
4549    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) {
4550        ce->refcount--;
4551        if (!compile_time) {
4552            /* If we're in compile time, in practice, it's quite possible
4553             * that we'll never reach this class declaration at runtime,
4554             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
4555             * approach to work.
4556             */
4557            zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4558        }
4559        return NULL;
4560    } else {
4561        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
4562            zend_verify_abstract_class(ce TSRMLS_CC);
4563        }
4564        return ce;
4565    }
4566}
4567/* }}} */
4568
4569ZEND_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) /* {{{ */
4570{
4571    zend_class_entry *ce, **pce;
4572    int found_ce;
4573    zval *op1, *op2;
4574
4575    if (compile_time) {
4576        op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4577        op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4578    } else {
4579        op1 = opline->op1.zv;
4580        op2 = opline->op2.zv;
4581    }
4582
4583    found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce);
4584
4585    if (found_ce == FAILURE) {
4586        if (!compile_time) {
4587            /* If we're in compile time, in practice, it's quite possible
4588             * that we'll never reach this class declaration at runtime,
4589             * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
4590             * approach to work.
4591             */
4592            zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
4593        }
4594        return NULL;
4595    } else {
4596        ce = *pce;
4597    }
4598
4599    if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
4600        zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name);
4601    } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
4602        zend_error(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name, parent_ce->name);
4603    }
4604
4605    zend_do_inheritance(ce, parent_ce TSRMLS_CC);
4606
4607    ce->refcount++;
4608
4609    /* Register the derived class */
4610    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) {
4611        zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4612    }
4613    return ce;
4614}
4615/* }}} */
4616
4617void zend_do_early_binding(