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