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