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