diff options
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r-- | Zend/zend_compile.c | 1215 |
1 files changed, 641 insertions, 574 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 95d93903de..f018d10152 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -18,8 +18,6 @@ +----------------------------------------------------------------------+ */ -/* $Id$ */ - #include <zend_language_parser.h> #include "zend.h" #include "zend_compile.h" @@ -64,18 +62,20 @@ typedef struct _zend_loop_var { } u; } zend_loop_var; -static inline void zend_alloc_cache_slot(uint32_t literal) { +static inline uint32_t zend_alloc_cache_slot(void) { zend_op_array *op_array = CG(active_op_array); - Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size; + uint32_t ret = op_array->cache_size; op_array->cache_size += sizeof(void*); + return ret; } #define POLYMORPHIC_CACHE_SLOT_SIZE 2 -static inline void zend_alloc_polymorphic_cache_slot(uint32_t literal) { +static inline uint32_t zend_alloc_polymorphic_cache_slot(void) { zend_op_array *op_array = CG(active_op_array); - Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size; + uint32_t ret = op_array->cache_size; op_array->cache_size += POLYMORPHIC_CACHE_SLOT_SIZE * sizeof(void*); + return ret; } ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type); @@ -89,32 +89,43 @@ ZEND_API zend_executor_globals executor_globals; static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2); static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast); -static void zend_destroy_property_info_internal(zval *zv) /* {{{ */ +static void init_op(zend_op *op) { - zend_property_info *property_info = Z_PTR_P(zv); + MAKE_NOP(op); + op->extended_value = 0; + op->lineno = CG(zend_lineno); +} - zend_string_release(property_info->name); - free(property_info); +static zend_op *get_next_op(zend_op_array *op_array) +{ + uint32_t next_op_num = op_array->last++; + zend_op *next_op; + + if (UNEXPECTED(next_op_num >= CG(context).opcodes_size)) { + CG(context).opcodes_size *= 4; + op_array->opcodes = erealloc(op_array->opcodes, CG(context).opcodes_size * sizeof(zend_op)); + } + + next_op = &(op_array->opcodes[next_op_num]); + + init_op(next_op); + + return next_op; } -/* }}} */ -static void zend_destroy_class_constant_internal(zval *zv) /* {{{ */ +static zend_brk_cont_element *get_next_brk_cont_element(void) { - free(Z_PTR_P(zv)); + CG(context).last_brk_cont++; + CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont); + return &CG(context).brk_cont_array[CG(context).last_brk_cont-1]; } -/* }}} */ -static zend_string *zend_new_interned_string_safe(zend_string *str) /* {{{ */ { - zend_string *interned_str; +static void zend_destroy_property_info_internal(zval *zv) /* {{{ */ +{ + zend_property_info *property_info = Z_PTR_P(zv); - zend_string_addref(str); - interned_str = zend_new_interned_string(str); - if (str != interned_str) { - return interned_str; - } else { - zend_string_release(str); - return str; - } + zend_string_release_ex(property_info->name, 1); + free(property_info); } /* }}} */ @@ -287,7 +298,7 @@ static void zend_end_namespace(void) /* {{{ */ { FC(in_namespace) = 0; zend_reset_import_tables(); if (FC(current_namespace)) { - zend_string_release(FC(current_namespace)); + zend_string_release_ex(FC(current_namespace), 0); FC(current_namespace) = NULL; } } @@ -382,8 +393,9 @@ ZEND_API zend_string *zend_set_compiled_filename(zend_string *new_compiled_filen return Z_STR_P(p); } - ZVAL_STR_COPY(&rv, new_compiled_filename); - zend_hash_update(&CG(filenames_table), new_compiled_filename, &rv); + new_compiled_filename = zend_new_interned_string(zend_string_copy(new_compiled_filename)); + ZVAL_STR(&rv, new_compiled_filename); + zend_hash_add_new(&CG(filenames_table), new_compiled_filename, &rv); CG(compiled_filename) = new_compiled_filename; return new_compiled_filename; @@ -420,16 +432,14 @@ static uint32_t get_temporary_variable(zend_op_array *op_array) /* {{{ */ } /* }}} */ -static int lookup_cv(zend_op_array *op_array, zend_string* name) /* {{{ */{ +static int lookup_cv(zend_op_array *op_array, zend_string *name) /* {{{ */{ int i = 0; zend_ulong hash_value = zend_string_hash_val(name); while (i < op_array->last_var) { if (ZSTR_VAL(op_array->vars[i]) == ZSTR_VAL(name) || (ZSTR_H(op_array->vars[i]) == hash_value && - ZSTR_LEN(op_array->vars[i]) == ZSTR_LEN(name) && - memcmp(ZSTR_VAL(op_array->vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) { - zend_string_release(name); + zend_string_equal_content(op_array->vars[i], name))) { return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i); } i++; @@ -441,14 +451,14 @@ static int lookup_cv(zend_op_array *op_array, zend_string* name) /* {{{ */{ op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*)); } - op_array->vars[i] = zend_new_interned_string(name); + op_array->vars[i] = zend_string_copy(name); return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i); } /* }}} */ void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */ { - zval_dtor(CT_CONSTANT_EX(op_array, n)); + zval_ptr_dtor_nogc(CT_CONSTANT_EX(op_array, n)); if (n + 1 == op_array->last_literal) { op_array->last_literal--; } else { @@ -457,18 +467,23 @@ void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */ } /* }}} */ +static inline zend_string *zval_make_interned_string(zval *zv) /* {{{ */ +{ + ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); + Z_STR_P(zv) = zend_new_interned_string(Z_STR_P(zv)); + if (ZSTR_IS_INTERNED(Z_STR_P(zv))) { + Z_TYPE_FLAGS_P(zv) = 0; + } + return Z_STR_P(zv); +} + /* Common part of zend_add_literal and zend_append_individual_literal */ static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int literal_position) /* {{{ */ { - if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) { - zend_string_hash_val(Z_STR_P(zv)); - Z_STR_P(zv) = zend_new_interned_string(Z_STR_P(zv)); - if (ZSTR_IS_INTERNED(Z_STR_P(zv))) { - Z_TYPE_FLAGS_P(zv) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - } + if (Z_TYPE_P(zv) == IS_STRING) { + zval_make_interned_string(zv); } ZVAL_COPY_VALUE(CT_CONSTANT_EX(op_array, literal_position), zv); - Z_CACHE_SLOT(op_array->literals[literal_position]) = -1; } /* }}} */ @@ -546,8 +561,6 @@ static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *nam zend_string *lc_name = zend_string_tolower(name); zend_add_literal_string(op_array, &lc_name); - zend_alloc_cache_slot(ret); - return ret; } /* }}} */ @@ -621,68 +634,6 @@ static uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) / } /* }}} */ -static uint32_t zend_start_live_range_ex(zend_op_array *op_array, uint32_t start) /* {{{ */ -{ - if (op_array->last_live_range == 0 || - op_array->live_range[op_array->last_live_range - 1].start <= start) { - return zend_start_live_range(op_array, start); - } else { - /* Live ranges have to be sorted by "start" field */ - uint32_t n = op_array->last_live_range; - - /* move early ranges to make a room */ - op_array->last_live_range = n + 1; - op_array->live_range = erealloc(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range); - do { - op_array->live_range[n] = op_array->live_range[n-1]; - n--; - } while (n != 0 && op_array->live_range[n-1].start > start); - - /* initialize new range */ - op_array->live_range[n].start = start; - - /* update referens to live-ranges from stack */ - if (!zend_stack_is_empty(&CG(loop_var_stack))) { - zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack)); - zend_loop_var *base = zend_stack_base(&CG(loop_var_stack)); - int check_opcodes = 0; - - for (; loop_var >= base; loop_var--) { - if (loop_var->opcode == ZEND_RETURN) { - /* Stack separator */ - break; - } else if (loop_var->opcode == ZEND_FREE || - loop_var->opcode == ZEND_FE_FREE) { - if (loop_var->u.live_range_offset >= n) { - loop_var->u.live_range_offset++; - check_opcodes = 1; - } else { - break; - } - } - } - - /* update previously generated FREE/FE_FREE opcodes */ - if (check_opcodes) { - zend_op *opline = op_array->opcodes + op_array->live_range[n+1].start; - zend_op *end = op_array->opcodes + op_array->last; - - while (opline < end) { - if ((opline->opcode == ZEND_FREE || - opline->opcode == ZEND_FE_FREE) && - (opline->extended_value & ZEND_FREE_ON_RETURN) && - opline->op2.num >= n) { - opline->op2.num++; - } - opline++; - } - } - } - return n; - } -} -/* }}} */ - static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end, uint32_t kind, uint32_t var) /* {{{ */ { zend_live_range *range = op_array->live_range + offset; @@ -696,7 +647,8 @@ static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32 } /* }}} */ -static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var) /* {{{ */ +static inline void zend_begin_loop( + zend_uchar free_opcode, const znode *loop_var, zend_bool is_switch) /* {{{ */ { zend_brk_cont_element *brk_cont_element; int parent = CG(context).current_brk_cont; @@ -705,6 +657,7 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var CG(context).current_brk_cont = CG(context).last_brk_cont; brk_cont_element = get_next_brk_cont_element(); brk_cont_element->parent = parent; + brk_cont_element->is_switch = is_switch; if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) { uint32_t start = get_next_op_number(CG(active_op_array)); @@ -770,15 +723,7 @@ void zend_do_free(znode *op1) /* {{{ */ } if (opline->result_type == IS_VAR && opline->result.var == op1->u.op.var) { - if (opline->opcode == ZEND_FETCH_R || - opline->opcode == ZEND_FETCH_DIM_R || - opline->opcode == ZEND_FETCH_OBJ_R || - opline->opcode == ZEND_FETCH_STATIC_PROP_R) { - /* It's very rare and useless case. It's better to use - additional FREE opcode and simplify the FETCH handlers - their selves */ - zend_emit_op(NULL, ZEND_FREE, op1, NULL); - } else if (opline->opcode == ZEND_FETCH_THIS) { + if (opline->opcode == ZEND_FETCH_THIS) { opline->opcode = ZEND_NOP; opline->result_type = IS_UNUSED; } else { @@ -786,7 +731,8 @@ void zend_do_free(znode *op1) /* {{{ */ } } else { while (opline >= CG(active_op_array)->opcodes) { - if (opline->opcode == ZEND_FETCH_LIST && + if ((opline->opcode == ZEND_FETCH_LIST_R || + opline->opcode == ZEND_FETCH_LIST_W) && opline->op1_type == IS_VAR && opline->op1.var == op1->u.op.var) { zend_emit_op(NULL, ZEND_FREE, op1, NULL); @@ -815,13 +761,18 @@ uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ { uint32_t new_flags = flags | new_flag; if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, + "Multiple abstract modifiers are not allowed", 0); + return 0; } if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0); + return 0; } if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class"); + zend_throw_exception(zend_ce_compile_error, + "Cannot use the final modifier on an abstract class", 0); + return 0; } return new_flags; } @@ -831,19 +782,26 @@ uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ { uint32_t new_flags = flags | new_flag; if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, + "Multiple access type modifiers are not allowed", 0); + return 0; } if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, "Multiple abstract modifiers are not allowed", 0); + return 0; } if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple static modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, "Multiple static modifiers are not allowed", 0); + return 0; } if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) { - zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed"); + zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0); + return 0; } if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member"); + zend_throw_exception(zend_ce_compile_error, + "Cannot use the final modifier on an abstract class member", 0); + return 0; } return new_flags; } @@ -1026,7 +984,7 @@ static void label_ptr_dtor(zval *zv) /* {{{ */ /* }}} */ static void str_dtor(zval *zv) /* {{{ */ { - zend_string_release(Z_STR_P(zv)); + zend_string_release_ex(Z_STR_P(zv), 0); } /* }}} */ @@ -1061,7 +1019,7 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */ } if (op_array->static_variables) { if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(op_array->static_variables)++; + GC_ADDREF(op_array->static_variables); } } op_array->run_time_cache = NULL; @@ -1076,25 +1034,28 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */ ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */ { zend_function *function, *new_function; - zval *lcname, *rtd_key; + zval *lcname, *rtd_key, *zv; if (compile_time) { lcname = CT_CONSTANT_EX(op_array, opline->op1.constant); rtd_key = lcname + 1; } else { - lcname = RT_CONSTANT(op_array, opline->op1); + lcname = RT_CONSTANT(opline, opline->op1); rtd_key = lcname + 1; } - function = zend_hash_find_ptr(function_table, Z_STR_P(rtd_key)); + zv = zend_hash_find_ex(function_table, Z_STR_P(rtd_key), 1); + function = (zend_function*)Z_PTR_P(zv); new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_function, function, sizeof(zend_op_array)); if (zend_hash_add_ptr(function_table, Z_STR_P(lcname), new_function) == NULL) { int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; zend_function *old_function; - if ((old_function = zend_hash_find_ptr(function_table, Z_STR_P(lcname))) != NULL - && old_function->type == ZEND_USER_FUNCTION + zv = zend_hash_find_ex(function_table, Z_STR_P(lcname), 1); + ZEND_ASSERT(zv != NULL); + old_function = (zend_function*)Z_PTR_P(zv); + if (old_function->type == ZEND_USER_FUNCTION && old_function->op_array.last > 0) { zend_error_noreturn(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", ZSTR_VAL(function->common.function_name), @@ -1108,7 +1069,9 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opli if (function->op_array.refcount) { (*function->op_array.refcount)++; } - function->op_array.static_variables = NULL; /* NULL out the unbound function */ + if (!(function->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) { + function->op_array.static_variables = NULL; /* NULL out the unbound function */ + } return SUCCESS; } } @@ -1117,17 +1080,18 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opli ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time) /* {{{ */ { zend_class_entry *ce; - zval *lcname, *rtd_key; + zval *lcname, *rtd_key, *zv; if (compile_time) { lcname = CT_CONSTANT_EX(op_array, opline->op1.constant); rtd_key = lcname + 1; } else { - lcname = RT_CONSTANT(op_array, opline->op1); + lcname = RT_CONSTANT(opline, opline->op1); rtd_key = lcname + 1; } - ce = zend_hash_find_ptr(class_table, Z_STR_P(rtd_key)); - ZEND_ASSERT(ce); + zv = zend_hash_find_ex(class_table, Z_STR_P(rtd_key), 1); + ZEND_ASSERT(zv); + ce = (zend_class_entry*)Z_PTR_P(zv); ce->refcount++; if (zend_hash_add_ptr(class_table, Z_STR_P(lcname), ce) == NULL) { ce->refcount--; @@ -1152,19 +1116,19 @@ ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const ze ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time) /* {{{ */ { zend_class_entry *ce; - zval *lcname, *rtd_key; + zval *lcname, *rtd_key, *zv; if (compile_time) { lcname = CT_CONSTANT_EX(op_array, opline->op1.constant); rtd_key = lcname + 1; } else { - lcname = RT_CONSTANT(op_array, opline->op1); + lcname = RT_CONSTANT(opline, opline->op1); rtd_key = lcname + 1; } - ce = zend_hash_find_ptr(class_table, Z_STR_P(rtd_key)); + zv = zend_hash_find_ex(class_table, Z_STR_P(rtd_key), 1); - if (!ce) { + if (!zv) { if (!compile_time) { /* If we're in compile time, in practice, it's quite possible * that we'll never reach this class declaration at runtime, @@ -1176,6 +1140,8 @@ ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array return NULL; } + ce = (zend_class_entry*)Z_PTR_P(zv); + if (zend_hash_exists(class_table, Z_STR_P(lcname))) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name)); } @@ -1216,21 +1182,15 @@ void zend_do_early_binding(void) /* {{{ */ break; case ZEND_DECLARE_INHERITED_CLASS: { - zend_op *fetch_class_opline = opline-1; zval *parent_name; zend_class_entry *ce; - parent_name = CT_CONSTANT(fetch_class_opline->op2); + parent_name = CT_CONSTANT(opline->op2); if (((ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0)) == NULL) || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && (ce->type == ZEND_INTERNAL_CLASS))) { if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { - uint32_t *opline_num = &CG(active_op_array)->early_binding; - - while (*opline_num != (uint32_t)-1) { - opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num; - } - *opline_num = opline - CG(active_op_array)->opcodes; + CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING; opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; opline->result_type = IS_UNUSED; opline->result.opline_num = -1; @@ -1240,9 +1200,8 @@ void zend_do_early_binding(void) /* {{{ */ if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), ce, 1) == NULL) { return; } - /* clear unnecessary ZEND_FETCH_CLASS opcode */ - zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant); - MAKE_NOP(fetch_class_opline); + zend_del_literal(CG(active_op_array), opline->op2.constant+1); + zend_del_literal(CG(active_op_array), opline->op2.constant); table = CG(class_table); break; @@ -1278,7 +1237,7 @@ static void zend_mark_function_as_generator() /* {{{ */ if (ZEND_TYPE_CODE(return_info.type) != IS_ITERABLE) { const char *msg = "Generators may only declare a return type of Generator, Iterator, Traversable, or iterable, %s is not permitted"; - + if (!ZEND_TYPE_IS_CLASS(return_info.type)) { zend_error_noreturn(E_COMPILE_ERROR, msg, zend_get_type_by_const(ZEND_TYPE_CODE(return_info.type))); } @@ -1295,16 +1254,39 @@ static void zend_mark_function_as_generator() /* {{{ */ } /* }}} */ -ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array) /* {{{ */ +ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array) /* {{{ */ { - if (op_array->early_binding != (uint32_t)-1) { + if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { + uint32_t first_early_binding_opline = (uint32_t)-1; + uint32_t *prev_opline_num = &first_early_binding_opline; + zend_op *opline = op_array->opcodes; + zend_op *end = opline + op_array->last; + + while (opline < end) { + if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { + *prev_opline_num = opline - op_array->opcodes; + prev_opline_num = &opline->result.opline_num; + } + ++opline; + } + *prev_opline_num = -1; + return first_early_binding_opline; + } + return (uint32_t)-1; +} +/* }}} */ + +ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */ +{ + if (first_early_binding_opline != (uint32_t)-1) { zend_bool orig_in_compilation = CG(in_compilation); - uint32_t opline_num = op_array->early_binding; + uint32_t opline_num = first_early_binding_opline; zend_class_entry *ce; CG(in_compilation) = 1; while (opline_num != (uint32_t)-1) { - zval *parent_name = RT_CONSTANT(op_array, op_array->opcodes[opline_num-1].op2); + const zend_op *opline = &op_array->opcodes[opline_num]; + zval *parent_name = RT_CONSTANT(opline, opline->op2); if ((ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0)) != NULL) { do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), ce, 0); } @@ -1384,7 +1366,7 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char static zend_constant *zend_lookup_reserved_const(const char *name, size_t len) /* {{{ */ { zend_constant *c = zend_hash_find_ptr_lc(EG(zend_constants), name, len); - if (c && !(c->flags & CONST_CS) && (c->flags & CONST_CT_SUBST)) { + if (c && !(ZEND_CONSTANT_FLAGS(c) & CONST_CS) && (ZEND_CONSTANT_FLAGS(c) & CONST_CT_SUBST)) { return c; } return NULL; @@ -1398,10 +1380,12 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i /* Substitute case-sensitive (or lowercase) constants */ c = zend_hash_find_ptr(EG(zend_constants), name); if (c && ( - ((c->flags & CONST_PERSISTENT) && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION)) + ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) + && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) + && (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE) || !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) || (Z_TYPE(c->value) < IS_OBJECT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) )) { - ZVAL_DUP(zv, &c->value); + ZVAL_COPY_OR_DUP(zv, &c->value); return 1; } @@ -1416,7 +1400,7 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i c = zend_lookup_reserved_const(lookup_name, lookup_len); if (c) { - ZVAL_DUP(zv, &c->value); + ZVAL_COPY_OR_DUP(zv, &c->value); return 1; } } @@ -1569,7 +1553,7 @@ static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, /* Substitute case-sensitive (or lowercase) persistent class constants */ if (Z_TYPE_P(c) < IS_OBJECT) { - ZVAL_DUP(zv, c); + ZVAL_COPY_OR_DUP(zv, c); return 1; } @@ -1608,8 +1592,6 @@ void zend_do_extended_info(void) /* {{{ */ opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_EXT_STMT; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); } /* }}} */ @@ -1624,8 +1606,6 @@ void zend_do_extended_fcall_begin(void) /* {{{ */ opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_EXT_FCALL_BEGIN; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); } /* }}} */ @@ -1640,8 +1620,6 @@ void zend_do_extended_fcall_end(void) /* {{{ */ opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_EXT_FCALL_END; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); } /* }}} */ @@ -1677,13 +1655,12 @@ int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global zend_auto_global auto_global; int retval; - auto_global.name = zend_new_interned_string(name); + auto_global.name = name; auto_global.auto_global_callback = auto_global_callback; auto_global.jit = jit; retval = zend_hash_add_mem(CG(auto_globals), auto_global.name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE; - zend_string_release(name); return retval; } /* }}} */ @@ -1704,44 +1681,16 @@ ZEND_API void zend_activate_auto_globals(void) /* {{{ */ } /* }}} */ -int zendlex(zend_parser_stack_elem *elem) /* {{{ */ +int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem) /* {{{ */ { zval zv; - int retval; - uint32_t start_lineno; if (CG(increment_lineno)) { CG(zend_lineno)++; CG(increment_lineno) = 0; } -again: - ZVAL_UNDEF(&zv); - start_lineno = CG(zend_lineno); - retval = lex_scan(&zv); - if (EG(exception)) { - return T_ERROR; - } - - switch (retval) { - case T_COMMENT: - case T_DOC_COMMENT: - case T_OPEN_TAG: - case T_WHITESPACE: - goto again; - - case T_CLOSE_TAG: - retval = ';'; /* implicit ; */ - break; - case T_OPEN_TAG_WITH_ECHO: - retval = T_ECHO; - break; - } - if (Z_TYPE(zv) != IS_UNDEF) { - elem->ast = zend_ast_create_zval_with_lineno(&zv, 0, start_lineno); - } - - return retval; + return lex_scan(&zv, elem); } /* }}} */ @@ -1759,7 +1708,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->default_properties_table = NULL; ce->default_static_members_table = NULL; zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : NULL), persistent_hashes, 0); - zend_hash_init_ex(&ce->constants_table, 8, NULL, (persistent_hashes ? zend_destroy_class_constant_internal : NULL), persistent_hashes, 0); + zend_hash_init_ex(&ce->constants_table, 8, NULL, NULL, persistent_hashes, 0); zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); if (ce->type == ZEND_INTERNAL_CLASS) { @@ -1797,8 +1746,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->__tostring = NULL; ce->create_object = NULL; ce->get_iterator = NULL; - ce->iterator_funcs.funcs = NULL; - ce->interface_gets_implemented = NULL; + ce->iterator_funcs_ptr = NULL; ce->get_static_method = NULL; ce->parent = NULL; ce->num_interfaces = 0; @@ -1840,7 +1788,7 @@ zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */ ZSTR_VAL(result)[left_len] = '\\'; memcpy(&ZSTR_VAL(result)[left_len + 1], ZSTR_VAL(right), ZSTR_LEN(right)); ZSTR_VAL(result)[len] = '\0'; - zend_string_release(right); + zend_string_release_ex(right, 0); ZVAL_STR(left_zv, result); return left_ast; @@ -1944,16 +1892,14 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* }}} */ -static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */ +static void zend_adjust_for_fetch_type(zend_op *opline, znode *result, uint32_t type) /* {{{ */ { zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; - - if (opline->opcode == ZEND_FETCH_THIS) { - return; - } - switch (type & BP_VAR_MASK) { + switch (type) { case BP_VAR_R: + opline->result_type = IS_TMP_VAR; + result->op_type = IS_TMP_VAR; return; case BP_VAR_W: opline->opcode += 1 * factor; @@ -1962,11 +1908,12 @@ static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */ opline->opcode += 2 * factor; return; case BP_VAR_IS: + opline->result_type = IS_TMP_VAR; + result->op_type = IS_TMP_VAR; opline->opcode += 3 * factor; return; case BP_VAR_FUNC_ARG: opline->opcode += 4 * factor; - opline->extended_value |= type >> BP_VAR_SHIFT; return; case BP_VAR_UNSET: opline->opcode += 5 * factor; @@ -2022,14 +1969,41 @@ static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var) } else if (def->opcode == ZEND_NEW) { /* Objects created via ZEND_NEW are only fully initialized * after the DO_FCALL (constructor call) */ - def = CG(active_op_array)->opcodes + def->op2.opline_num - 1; + int level = 0; + while (def + 1 != opline) { + def++; + if (def->opcode == ZEND_DO_FCALL) { + if (level == 0) { + break; + } + level--; + } else { + switch(def->opcode) { + case ZEND_INIT_FCALL: + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_DYNAMIC_CALL: + case ZEND_INIT_USER_CALL: + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_NEW: + level++; + break; + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: + level--; + break; + } + } + } if (def + 1 == opline) { break; } } zend_end_live_range(CG(active_op_array), - zend_start_live_range_ex(CG(active_op_array), + zend_start_live_range(CG(active_op_array), def + 1 - CG(active_op_array)->opcodes), opline - CG(active_op_array)->opcodes, ZEND_LIVE_TMPVAR, var); @@ -2091,7 +2065,8 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ opline->opcode == ZEND_ROPE_ADD || opline->opcode == ZEND_ROPE_END || opline->opcode == ZEND_END_SILENCE || - opline->opcode == ZEND_FETCH_LIST || + opline->opcode == ZEND_FETCH_LIST_R || + opline->opcode == ZEND_FETCH_LIST_W || opline->opcode == ZEND_VERIFY_RETURN_TYPE || opline->opcode == ZEND_BIND_LEXICAL) { /* these opcodes are handled separately */ @@ -2129,15 +2104,11 @@ static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode zend_op *opline = get_next_op(CG(active_op_array)); opline->opcode = opcode; - if (op1 == NULL) { - SET_UNUSED(opline->op1); - } else { + if (op1 != NULL) { SET_NODE(opline->op1, op1); } - if (op2 == NULL) { - SET_UNUSED(opline->op2); - } else { + if (op2 != NULL) { SET_NODE(opline->op2, op2); } @@ -2155,15 +2126,11 @@ static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, z zend_op *opline = get_next_op(CG(active_op_array)); opline->opcode = opcode; - if (op1 == NULL) { - SET_UNUSED(opline->op1); - } else { + if (op1 != NULL) { SET_NODE(opline->op1, op1); } - if (op2 == NULL) { - SET_UNUSED(opline->op2); - } else { + if (op2 != NULL) { SET_NODE(opline->op2, op2); } @@ -2185,12 +2152,10 @@ static void zend_emit_tick(void) /* {{{ */ if (CG(active_op_array)->last && CG(active_op_array)->opcodes[CG(active_op_array)->last - 1].opcode == ZEND_TICKS) { return; } - + opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_TICKS; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); opline->extended_value = FC(declarables).ticks; } /* }}} */ @@ -2282,16 +2247,14 @@ static inline void zend_update_jump_target_to_next(uint32_t opnum_jump) /* {{{ * static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */ { zend_op tmp_opline; + init_op(&tmp_opline); + tmp_opline.opcode = opcode; - if (op1 == NULL) { - SET_UNUSED(tmp_opline.op1); - } else { + if (op1 != NULL) { SET_NODE(tmp_opline.op1, op1); } - if (op2 == NULL) { - SET_UNUSED(tmp_opline.op2); - } else { + if (op2 != NULL) { SET_NODE(tmp_opline.op2, op2); } if (result) { @@ -2465,6 +2428,26 @@ static inline void zend_handle_numeric_op(znode *node) /* {{{ */ } /* }}} */ +static inline void zend_handle_numeric_dim(zend_op *opline, znode *dim_node) /* {{{ */ +{ + if (Z_TYPE(dim_node->u.constant) == IS_STRING) { + zend_ulong index; + + if (ZEND_HANDLE_NUMERIC(Z_STR(dim_node->u.constant), index)) { + /* For numeric indexs we also keep the original value to use by ArrayAccess + * See bug #63217 + */ + int c = zend_add_literal(CG(active_op_array), &dim_node->u.constant); + ZEND_ASSERT(opline->op2.constant + 1 == c); + ZVAL_LONG(CT_CONSTANT(opline->op2), index); + Z_EXTRA_P(CT_CONSTANT(opline->op2)) = ZEND_EXTRA_VALUE; + return; + } + } + Z_EXTRA_P(CT_CONSTANT(opline->op2)) = 0; +} +/* }}} */ + static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) /* {{{ */ { if (class_node->op_type == IS_CONST) { @@ -2477,45 +2460,6 @@ static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) / } /* }}} */ -static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast, int throw_exception) /* {{{ */ -{ - zend_op *opline; - znode name_node; - zend_compile_expr(&name_node, name_ast); - - if (name_node.op_type == IS_CONST) { - zend_string *name; - uint32_t fetch_type; - - if (Z_TYPE(name_node.u.constant) != IS_STRING) { - zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name"); - } - - name = Z_STR(name_node.u.constant); - fetch_type = zend_get_class_fetch_type(name); - - opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, NULL); - opline->extended_value = fetch_type | (throw_exception ? ZEND_FETCH_CLASS_EXCEPTION : 0); - - if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) { - uint32_t type = name_ast->kind == ZEND_AST_ZVAL ? name_ast->attr : ZEND_NAME_FQ; - opline->op2_type = IS_CONST; - opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), - zend_resolve_class_name(name, type)); - } else { - zend_ensure_valid_class_fetch_type(fetch_type); - } - - zend_string_release(name); - } else { - opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node); - opline->extended_value = ZEND_FETCH_CLASS_DEFAULT | (throw_exception ? ZEND_FETCH_CLASS_EXCEPTION : 0); - } - - return opline; -} -/* }}} */ - static void zend_compile_class_ref_ex(znode *result, zend_ast *name_ast, uint32_t fetch_flags) /* {{{ */ { uint32_t fetch_type; @@ -2544,10 +2488,10 @@ static void zend_compile_class_ref_ex(znode *result, zend_ast *name_ast, uint32_ result->u.op.num = fetch_type | fetch_flags; } - zend_string_release(name); + zend_string_release_ex(name, 0); } else { zend_op *opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node); - opline->extended_value = ZEND_FETCH_CLASS_DEFAULT | fetch_flags; + opline->op1.num = ZEND_FETCH_CLASS_DEFAULT | fetch_flags; } return; } @@ -2575,18 +2519,25 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *name_ast = ast->child[0]; if (name_ast->kind == ZEND_AST_ZVAL) { - zend_string *name = zval_get_string(zend_ast_get_zval(name_ast)); + zval *zv = zend_ast_get_zval(name_ast); + zend_string *name; + + if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) { + name = zval_make_interned_string(zv); + } else { + name = zend_new_interned_string(zval_get_string_func(zv)); + } if (zend_is_auto_global(name)) { - zend_string_release(name); return FAILURE; } result->op_type = IS_CV; result->u.op.var = lookup_cv(CG(active_op_array), name); - /* lookup_cv may be using another zend_string instance */ - name = CG(active_op_array)->vars[EX_VAR_TO_NUM(result->u.op.var)]; + if (UNEXPECTED(Z_TYPE_P(zv) != IS_STRING)) { + zend_string_release_ex(name, 0); + } return SUCCESS; } @@ -2612,7 +2563,7 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL); } - if (name_node.op_type == IS_CONST && + if (name_node.op_type == IS_CONST && zend_is_auto_global(Z_STR(name_node.u.constant))) { opline->extended_value = ZEND_FETCH_GLOBAL; @@ -2620,6 +2571,7 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint opline->extended_value = ZEND_FETCH_LOCAL; } + zend_adjust_for_fetch_type(opline, result, type); return opline; } /* }}} */ @@ -2637,14 +2589,14 @@ static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */ static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ { - zend_op *opline; - if (is_this_fetch(ast)) { - opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL); - zend_adjust_for_fetch_type(opline, type); + zend_op *opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL); + if ((type == BP_VAR_R) || (type == BP_VAR_IS)) { + opline->result_type = IS_TMP_VAR; + result->op_type = IS_TMP_VAR; + } } else if (zend_try_compile_cv(result, ast) == FAILURE) { - zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type, delayed); - zend_adjust_for_fetch_type(opline, type); + zend_compile_simple_var_no_cv(result, ast, type, delayed); } } /* }}} */ @@ -2665,18 +2617,13 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type); void zend_compile_assign(znode *result, zend_ast *ast); -static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style); static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */ { znode dummy_node; - if (var_ast->kind == ZEND_AST_ARRAY) { - zend_compile_list_assign(&dummy_node, var_ast, value_node, var_ast->attr); - } else { - zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, - zend_ast_create_znode(value_node)); - zend_compile_assign(&dummy_node, assign_ast); - } + zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, + zend_ast_create_znode(value_node)); + zend_compile_assign(&dummy_node, assign_ast); zend_do_free(&dummy_node); } /* }}} */ @@ -2685,6 +2632,7 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t { zend_ast *var_ast = ast->child[0]; zend_ast *dim_ast = ast->child[1]; + zend_op *opline; znode var_node, dim_node; @@ -2701,14 +2649,19 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t dim_node.op_type = IS_UNUSED; } else { zend_compile_expr(&dim_node, dim_ast); - zend_handle_numeric_op(&dim_node); } - return zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node); + opline = zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node); + zend_adjust_for_fetch_type(opline, result, type); + + if (dim_node.op_type == IS_CONST) { + zend_handle_numeric_dim(opline, &dim_node); + } + return opline; } /* }}} */ -static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { uint32_t offset = zend_delayed_compile_begin(); zend_delayed_compile_dim(result, ast, type); @@ -2716,13 +2669,6 @@ static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uin } /* }}} */ -void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ -{ - zend_op *opline = zend_compile_dim_common(result, ast, type); - zend_adjust_for_fetch_type(opline, type); -} -/* }}} */ - static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { zend_ast *obj_ast = ast->child[0]; @@ -2742,14 +2688,15 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node); if (opline->op2_type == IS_CONST) { convert_to_string(CT_CONSTANT(opline->op2)); - zend_alloc_polymorphic_cache_slot(opline->op2.constant); + opline->extended_value = zend_alloc_polymorphic_cache_slot(); } + zend_adjust_for_fetch_type(opline, result, type); return opline; } /* }}} */ -static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static zend_op *zend_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { uint32_t offset = zend_delayed_compile_begin(); zend_delayed_compile_prop(result, ast, type); @@ -2757,14 +2704,7 @@ static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t } /* }}} */ -void zend_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ -{ - zend_op *opline = zend_compile_prop_common(result, ast, type); - zend_adjust_for_fetch_type(opline, type); -} -/* }}} */ - -zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ +zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ { zend_ast *class_ast = ast->child[0]; zend_ast *prop_ast = ast->child[1]; @@ -2783,27 +2723,24 @@ zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t } if (opline->op1_type == IS_CONST) { convert_to_string(CT_CONSTANT(opline->op1)); - zend_alloc_polymorphic_cache_slot(opline->op1.constant); + opline->extended_value = zend_alloc_polymorphic_cache_slot(); } if (class_node.op_type == IS_CONST) { opline->op2_type = IS_CONST; opline->op2.constant = zend_add_class_name_literal( CG(active_op_array), Z_STR(class_node.u.constant)); + if (opline->op1_type != IS_CONST) { + opline->extended_value = zend_alloc_cache_slot(); + } } else { SET_NODE(opline->op2, &class_node); } + zend_adjust_for_fetch_type(opline, result, type); return opline; } /* }}} */ -void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ -{ - zend_op *opline = zend_compile_static_prop_common(result, ast, type, delayed); - zend_adjust_for_fetch_type(opline, type); -} -/* }}} */ - static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_style) /* {{{ */ { if (var_ast->kind == ZEND_AST_ARRAY) { if (var_ast->attr == ZEND_ARRAY_SYNTAX_LONG) { @@ -2818,6 +2755,30 @@ static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_styl } /* }}} */ +static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node); + +/* Propagate refs used on leaf elements to the surrounding list() structures. */ +static zend_bool zend_propagate_list_refs(zend_ast *ast) { /* {{{ */ + zend_ast_list *list = zend_ast_get_list(ast); + zend_bool has_refs = 0; + uint32_t i; + + for (i = 0; i < list->children; ++i) { + zend_ast *elem_ast = list->child[i]; + + if (elem_ast) { + zend_ast *var_ast = elem_ast->child[0]; + if (var_ast->kind == ZEND_AST_ARRAY) { + elem_ast->attr = zend_propagate_list_refs(var_ast); + } + has_refs |= elem_ast->attr; + } + } + + return has_refs; +} +/* }}} */ + static void zend_compile_list_assign( znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style) /* {{{ */ { @@ -2827,10 +2788,15 @@ static void zend_compile_list_assign( zend_bool is_keyed = list->children > 0 && list->child[0] != NULL && list->child[0]->child[1] != NULL; + if (list->children && expr_node->op_type == IS_CONST && Z_TYPE(expr_node->u.constant) == IS_STRING) { + zval_make_interned_string(&expr_node->u.constant); + } + for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; zend_ast *var_ast, *key_ast; znode fetch_result, dim_node; + zend_op *opline; if (elem_ast == NULL) { if (is_keyed) { @@ -2841,10 +2807,6 @@ static void zend_compile_list_assign( } } - if (elem_ast->attr) { - zend_error(E_COMPILE_ERROR, "[] and list() assignments cannot be by reference"); - } - var_ast = elem_ast->child[0]; key_ast = elem_ast->child[1]; has_elems = 1; @@ -2872,15 +2834,34 @@ static void zend_compile_list_assign( zend_verify_list_assign_target(var_ast, old_style); - zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node); - zend_emit_assign_znode(var_ast, &fetch_result); + opline = zend_emit_op(&fetch_result, + elem_ast->attr ? (expr_node->op_type == IS_CV ? ZEND_FETCH_DIM_W : ZEND_FETCH_LIST_W) : ZEND_FETCH_LIST_R, expr_node, &dim_node); + + if (dim_node.op_type == IS_CONST) { + zend_handle_numeric_dim(opline, &dim_node); + } + + if (var_ast->kind == ZEND_AST_ARRAY) { + if (elem_ast->attr) { + zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); + } + zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr); + } else if (elem_ast->attr) { + zend_emit_assign_ref_znode(var_ast, &fetch_result); + } else { + zend_emit_assign_znode(var_ast, &fetch_result); + } } if (has_elems == 0) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list"); } - *result = *expr_node; + if (result) { + *result = *expr_node; + } else { + zend_do_free(expr_node); + } } /* }}} */ @@ -2914,8 +2895,8 @@ zend_bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast) /* {{{ * zend_string *name1 = zval_get_string(zend_ast_get_zval(var_ast->child[0])); zend_string *name2 = zval_get_string(zend_ast_get_zval(expr_ast->child[0])); zend_bool result = zend_string_equals(name1, name2); - zend_string_release(name1); - zend_string_release(name2); + zend_string_release_ex(name1, 0); + zend_string_release_ex(name2, 0); return result; } } @@ -2943,7 +2924,7 @@ zend_bool zend_list_has_assign_to(zend_ast *list_ast, zend_string *name) /* {{{ if (var_ast->kind == ZEND_AST_VAR && var_ast->child[0]->kind == ZEND_AST_ZVAL) { zend_string *var_name = zval_get_string(zend_ast_get_zval(var_ast->child[0])); zend_bool result = zend_string_equals(var_name, name); - zend_string_release(var_name); + zend_string_release_ex(var_name, 0); if (result) { return 1; } @@ -2961,7 +2942,7 @@ zend_bool zend_list_has_assign_to_self(zend_ast *list_ast, zend_ast *expr_ast) / if (expr_ast->kind == ZEND_AST_VAR && expr_ast->child[0]->kind == ZEND_AST_ZVAL) { zend_string *name = zval_get_string(zend_ast_get_zval(expr_ast->child[0])); zend_bool result = zend_list_has_assign_to(list_ast, name); - zend_string_release(name); + zend_string_release_ex(name, 0); return result; } return 0; @@ -2999,7 +2980,13 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ if (zend_is_assign_to_self(var_ast, expr_ast) && !is_this_fetch(expr_ast)) { /* $a[0] = $a should evaluate the right $a first */ - zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + znode cv_node; + + if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) { + zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + } else { + zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); + } } else { zend_compile_expr(&expr_node, expr_ast); } @@ -3020,11 +3007,32 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ zend_emit_op_data(&expr_node); return; case ZEND_AST_ARRAY: - if (zend_list_has_assign_to_self(var_ast, expr_ast)) { - /* list($a, $b) = $a should evaluate the right $a first */ - zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + if (zend_propagate_list_refs(var_ast)) { + if (!zend_is_variable(expr_ast)) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot assign reference to non referencable value"); + } + + zend_compile_var(&expr_node, expr_ast, BP_VAR_W); + /* MAKE_REF is usually not necessary for CVs. However, if there are + * self-assignments, this forces the RHS to evaluate first. */ + if (expr_node.op_type != IS_CV + || zend_list_has_assign_to_self(var_ast, expr_ast)) { + zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); + } } else { - zend_compile_expr(&expr_node, expr_ast); + if (zend_list_has_assign_to_self(var_ast, expr_ast)) { + /* list($a, $b) = $a should evaluate the right $a first */ + znode cv_node; + + if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) { + zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + } else { + zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); + } + } else { + zend_compile_expr(&expr_node, expr_ast); + } } zend_compile_list_assign(result, var_ast, &expr_node, var_ast->attr); @@ -3094,7 +3102,7 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */ znode var_node, expr_node; zend_op *opline; - uint32_t offset; + uint32_t offset, cache_slot; zend_ensure_writable_variable(var_ast); @@ -3124,10 +3132,12 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); opline = zend_delayed_compile_end(offset); + cache_slot = opline->extended_value; opline->opcode = opcode; opline->extended_value = ZEND_ASSIGN_OBJ; - zend_emit_op_data(&expr_node); + opline = zend_emit_op_data(&expr_node); + opline->extended_value = cache_slot; return; EMPTY_SWITCH_DEFAULT_CASE() } @@ -3191,12 +3201,26 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ opcode = ZEND_SEND_REF; } else { zend_compile_var(&arg_node, arg, BP_VAR_R); - opcode = ZEND_SEND_VAR; + opcode = (arg_node.op_type == IS_TMP_VAR) ? ZEND_SEND_VAL : ZEND_SEND_VAR; } } else { - zend_compile_var(&arg_node, arg, - BP_VAR_FUNC_ARG | (arg_num << BP_VAR_SHIFT)); - opcode = ZEND_SEND_VAR_EX; + do { + if (arg->kind == ZEND_AST_VAR) { + CG(zend_lineno) = zend_ast_get_lineno(ast); + if (is_this_fetch(arg)) { + zend_emit_op(&arg_node, ZEND_FETCH_THIS, NULL, NULL); + opcode = ZEND_SEND_VAR_EX; + break; + } else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) { + opcode = ZEND_SEND_VAR_EX; + break; + } + } + opline = zend_emit_op(NULL, ZEND_CHECK_FUNC_ARG, NULL, NULL); + opline->op2.num = arg_num; + zend_compile_var(&arg_node, arg, BP_VAR_FUNC_ARG); + opcode = ZEND_SEND_FUNC_ARG; + } while (0); } } else { zend_compile_expr(&arg_node, arg); @@ -3313,11 +3337,10 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) / { zend_op *opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; - SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_ns_func_name_literal( CG(active_op_array), Z_STR(name_node->u.constant)); - zend_alloc_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); zend_compile_call_common(result, args_ast, NULL); } @@ -3338,16 +3361,16 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), class); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), method); - zend_alloc_cache_slot(opline->op2.constant); + /* 2 slots, for class and method */ + opline->result.num = zend_alloc_polymorphic_cache_slot(); zval_ptr_dtor(&name_node->u.constant); } else { zend_op *opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_INIT_FCALL_BY_NAME; - SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), str); - zend_alloc_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); } } else { zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node); @@ -3383,7 +3406,7 @@ int zend_compile_func_strlen(znode *result, zend_ast_list *args) /* {{{ */ if (arg_node.op_type == IS_CONST && Z_TYPE(arg_node.u.constant) == IS_STRING) { result->op_type = IS_CONST; ZVAL_LONG(&result->u.constant, Z_STRLEN(arg_node.u.constant)); - zval_dtor(&arg_node.u.constant); + zval_ptr_dtor_str(&arg_node.u.constant); } else { zend_emit_op_tmp(result, ZEND_STRLEN, &arg_node, NULL); } @@ -3402,7 +3425,11 @@ int zend_compile_func_typecheck(znode *result, zend_ast_list *args, uint32_t typ zend_compile_expr(&arg_node, args->child[0]); opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL); - opline->extended_value = type; + if (type != _IS_BOOL) { + opline->extended_value = (1 << type); + } else { + opline->extended_value = (1 << IS_FALSE) | (1 << IS_TRUE); + } return SUCCESS; } /* }}} */ @@ -3434,12 +3461,12 @@ int zend_compile_func_defined(znode *result, zend_ast_list *args) /* {{{ */ name = zval_get_string(zend_ast_get_zval(args->child[0])); if (zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)) || zend_memrchr(ZSTR_VAL(name), ':', ZSTR_LEN(name))) { - zend_string_release(name); + zend_string_release_ex(name, 0); return FAILURE; } if (zend_try_ct_eval_const(&result->u.constant, name, 0)) { - zend_string_release(name); + zend_string_release_ex(name, 0); zval_ptr_dtor(&result->u.constant); ZVAL_TRUE(&result->u.constant); result->op_type = IS_CONST; @@ -3449,7 +3476,7 @@ int zend_compile_func_defined(znode *result, zend_ast_list *args) /* {{{ */ opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL); opline->op1_type = IS_CONST; LITERAL_STR(opline->op1, name); - zend_alloc_cache_slot(opline->op1.constant); + opline->extended_value = zend_alloc_cache_slot(); /* Lowercase constant name in a separate literal */ { @@ -3514,7 +3541,7 @@ static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) ) { - zend_string_release(lcname); + zend_string_release_ex(lcname, 0); return FAILURE; } @@ -3523,7 +3550,7 @@ static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t opline->op1.num = zend_vm_calc_used_stack(num_args, fbc); opline->op2_type = IS_CONST; LITERAL_STR(opline->op2, lcname); - zend_alloc_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); return SUCCESS; } @@ -3582,11 +3609,11 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna opline = zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, &len_node); opline->extended_value = Z_LVAL_P(zv); zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); - zend_string_release(name); + zend_string_release_ex(name, 0); return SUCCESS; } } - zend_string_release(name); + zend_string_release_ex(name, 0); } zend_compile_expr(&arg_node, args->child[1]); zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL); @@ -3643,7 +3670,7 @@ static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string * opline->op2.constant = zend_add_ns_func_name_literal( CG(active_op_array), name); } - zend_alloc_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); if (args->children == 1 && (args->child[0]->kind != ZEND_AST_ZVAL || @@ -3661,7 +3688,7 @@ static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string * SET_NODE(opline->result, result); } else { if (!fbc) { - zend_string_release(name); + zend_string_release_ex(name, 0); } result->op_type = IS_CONST; ZVAL_TRUE(&result->u.constant); @@ -3688,11 +3715,11 @@ static int zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified); if (!zend_try_ct_eval_const(&value, resolved_name, is_fully_qualified)) { - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return FAILURE; } - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); strict = zend_is_true(&value); zval_ptr_dtor(&value); } else { @@ -3711,9 +3738,8 @@ static int zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ zend_bool ok = 1; zval *val, tmp; HashTable *src = Z_ARRVAL(array.u.constant); - HashTable *dst = emalloc(sizeof(HashTable)); + HashTable *dst = zend_new_array(zend_hash_num_elements(src)); - zend_hash_init(dst, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0); ZVAL_TRUE(&tmp); if (strict) { @@ -3860,10 +3886,10 @@ int zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */ first.op_type = IS_CONST; ZVAL_LONG(&first.u.constant, Z_LVAL_P(zv)); zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, &first, NULL); - zend_string_release(name); + zend_string_release_ex(name, 0); return SUCCESS; } - zend_string_release(name); + zend_string_release_ex(name, 0); } return FAILURE; } @@ -3987,7 +4013,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) ) { - zend_string_release(lcname); + zend_string_release_ex(lcname, 0); zend_compile_dynamic_call(result, &name_node, args_ast); return; } @@ -3995,7 +4021,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ if (zend_try_compile_special_func(result, lcname, zend_ast_get_list(args_ast), fbc, type) == SUCCESS ) { - zend_string_release(lcname); + zend_string_release_ex(lcname, 0); zval_ptr_dtor(&name_node.u.constant); return; } @@ -4004,7 +4030,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ ZVAL_NEW_STR(&name_node.u.constant, lcname); opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node); - zend_alloc_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); zend_compile_call_common(result, args_ast, fbc); } @@ -4038,7 +4064,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{ opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), Z_STR(method_node.u.constant)); - zend_alloc_polymorphic_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_polymorphic_cache_slot(); } else { SET_NODE(opline->op2, &method_node); } @@ -4099,12 +4125,11 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{ opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), Z_STR(method_node.u.constant)); + opline->result.num = zend_alloc_polymorphic_cache_slot(); + } else { if (opline->op1_type == IS_CONST) { - zend_alloc_cache_slot(opline->op2.constant); - } else { - zend_alloc_polymorphic_cache_slot(opline->op2.constant); + opline->result.num = zend_alloc_cache_slot(); } - } else { SET_NODE(opline->op2, &method_node); } zend_check_live_ranges(opline); @@ -4143,7 +4168,6 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ znode class_node, ctor_result; zend_op *opline; - uint32_t opnum; if (class_ast->kind == ZEND_AST_CLASS) { uint32_t dcl_opnum = get_next_op_number(CG(active_op_array)); @@ -4160,24 +4184,19 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ zend_compile_class_ref_ex(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION); } - opnum = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(result, ZEND_NEW, NULL, NULL); if (class_node.op_type == IS_CONST) { opline->op1_type = IS_CONST; opline->op1.constant = zend_add_class_name_literal( CG(active_op_array), Z_STR(class_node.u.constant)); + opline->op2.num = zend_alloc_cache_slot(); } else { SET_NODE(opline->op1, &class_node); } zend_compile_call_common(&ctor_result, args_ast, NULL); zend_do_free(&ctor_result); - - /* We save the position of DO_FCALL for convenience in find_live_range(). - * This info is not preserved for runtime. */ - opline = &CG(active_op_array)->opcodes[opnum]; - opline->op2.opline_num = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -4208,7 +4227,7 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable"); } else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) { zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node); - zend_alloc_cache_slot(opline->op2.constant); + opline->extended_value = zend_alloc_cache_slot(); } else { /* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W * to not free the name_node operand, so it can be reused in the following @@ -4228,37 +4247,43 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_bool by_ref) /* {{{ */ +static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, uint32_t by_ref) /* {{{ */ { znode var_node; zend_op *opline; + zend_string *var_name; - zend_compile_expr(&var_node, var_ast); + if (var_ast->kind == ZEND_AST_ZVAL) { + var_name = zval_make_interned_string(zend_ast_get_zval(var_ast)); + zend_compile_expr(&var_node, var_ast); + } else { + zend_compile_expr(&var_node, var_ast); + var_name = zval_make_interned_string(&var_node.u.constant); + } if (!CG(active_op_array)->static_variables) { if (CG(active_op_array)->scope) { CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; } - ALLOC_HASHTABLE(CG(active_op_array)->static_variables); - zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0); + CG(active_op_array)->static_variables = zend_new_array(8); } if (GC_REFCOUNT(CG(active_op_array)->static_variables) > 1) { if (!(GC_FLAGS(CG(active_op_array)->static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(CG(active_op_array)->static_variables)--; + GC_DELREF(CG(active_op_array)->static_variables); } CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables); } - zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); + value = zend_hash_update(CG(active_op_array)->static_variables, var_name, value); - if (zend_string_equals_literal(Z_STR(var_node.u.constant), "this")) { + if (zend_string_equals_literal(var_name, "this")) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable"); } opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node); opline->op1_type = IS_CV; - opline->op1.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR(var_node.u.constant))); - opline->extended_value = by_ref; + opline->op1.var = lookup_cv(CG(active_op_array), var_name); + opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | by_ref; } /* }}} */ @@ -4274,7 +4299,7 @@ void zend_compile_static_var(zend_ast *ast) /* {{{ */ ZVAL_NULL(&value_zv); } - zend_compile_static_var_common(var_ast, &value_zv, 1); + zend_compile_static_var_common(var_ast, &value_zv, ZEND_BIND_REF); } /* }}} */ @@ -4298,15 +4323,15 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */ } return; case ZEND_AST_DIM: - opline = zend_compile_dim_common(NULL, var_ast, BP_VAR_UNSET); + opline = zend_compile_dim(NULL, var_ast, BP_VAR_UNSET); opline->opcode = ZEND_UNSET_DIM; return; case ZEND_AST_PROP: - opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_UNSET); + opline = zend_compile_prop(NULL, var_ast, BP_VAR_UNSET); opline->opcode = ZEND_UNSET_OBJ; return; case ZEND_AST_STATIC_PROP: - opline = zend_compile_static_prop_common(NULL, var_ast, BP_VAR_UNSET, 0); + opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_UNSET, 0); opline->opcode = ZEND_UNSET_STATIC_PROP; return; EMPTY_SWITCH_DEFAULT_CASE() @@ -4330,11 +4355,8 @@ static int zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value opline->opcode = ZEND_FAST_CALL; opline->result_type = IS_TMP_VAR; opline->result.var = loop_var->var_num; - SET_UNUSED(opline->op1); if (return_value) { SET_NODE(opline->op2, return_value); - } else { - SET_UNUSED(opline->op2); } opline->op1.num = loop_var->u.try_catch_offset; } else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) { @@ -4342,7 +4364,6 @@ static int zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value opline->opcode = ZEND_DISCARD_EXCEPTION; opline->op1_type = IS_TMP_VAR; opline->op1.var = loop_var->var_num; - SET_UNUSED(opline->op2); } else if (loop_var->opcode == ZEND_RETURN) { /* Stack separator */ break; @@ -4359,8 +4380,6 @@ static int zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value opline->opcode = loop_var->opcode; opline->op1_type = loop_var->var_type; opline->op1.var = loop_var->var_num; - SET_UNUSED(opline->op2); - opline->op2.num = loop_var->u.live_range_offset; opline->extended_value = ZEND_FREE_ON_RETURN; depth--; } @@ -4498,13 +4517,13 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ if (depth_ast) { zval *depth_zv; if (depth_ast->kind != ZEND_AST_ZVAL) { - zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-constant operand " + zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-integer operand " "is no longer supported", ast->kind == ZEND_AST_BREAK ? "break" : "continue"); } depth_zv = zend_ast_get_zval(depth_ast); if (Z_TYPE_P(depth_zv) != IS_LONG || Z_LVAL_P(depth_zv) < 1) { - zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive numbers", + zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive integers", ast->kind == ZEND_AST_BREAK ? "break" : "continue"); } @@ -4523,6 +4542,29 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ depth, depth == 1 ? "" : "s"); } } + + if (ast->kind == ZEND_AST_CONTINUE) { + int d, cur = CG(context).current_brk_cont; + for (d = depth - 1; d > 0; d--) { + cur = CG(context).brk_cont_array[cur].parent; + ZEND_ASSERT(cur != -1); + } + + if (CG(context).brk_cont_array[cur].is_switch) { + if (depth == 1) { + zend_error(E_WARNING, + "\"continue\" targeting switch is equivalent to \"break\". " \ + "Did you mean to use \"continue %d\"?", + depth + 1); + } else { + zend_error(E_WARNING, + "\"continue %d\" targeting switch is equivalent to \"break %d\". " \ + "Did you mean to use \"continue %d\"?", + depth, depth, depth + 1); + } + } + } + opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT, NULL, NULL); opline->op1.num = CG(context).current_brk_cont; opline->op2.num = depth; @@ -4546,7 +4588,7 @@ void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label)); } - zval_dtor(label); + zval_ptr_dtor_str(label); ZVAL_NULL(label); current = opline->extended_value; @@ -4635,7 +4677,7 @@ void zend_compile_while(zend_ast *ast) /* {{{ */ opnum_jmp = zend_emit_jump(0); - zend_begin_loop(ZEND_NOP, NULL); + zend_begin_loop(ZEND_NOP, NULL, 0); opnum_start = get_next_op_number(CG(active_op_array)); zend_compile_stmt(stmt_ast); @@ -4658,7 +4700,7 @@ void zend_compile_do_while(zend_ast *ast) /* {{{ */ znode cond_node; uint32_t opnum_start, opnum_cond; - zend_begin_loop(ZEND_NOP, NULL); + zend_begin_loop(ZEND_NOP, NULL, 0); opnum_start = get_next_op_number(CG(active_op_array)); zend_compile_stmt(stmt_ast); @@ -4709,7 +4751,7 @@ void zend_compile_for(zend_ast *ast) /* {{{ */ opnum_jmp = zend_emit_jump(0); - zend_begin_loop(ZEND_NOP, NULL); + zend_begin_loop(ZEND_NOP, NULL, 0); opnum_start = get_next_op_number(CG(active_op_array)); zend_compile_stmt(stmt_ast); @@ -4755,6 +4797,10 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ value_ast = value_ast->child[0]; } + if (value_ast->kind == ZEND_AST_ARRAY && zend_propagate_list_refs(value_ast)) { + by_ref = 1; + } + if (by_ref && is_variable) { zend_compile_var(&expr_node, expr_ast, BP_VAR_W); } else { @@ -4768,7 +4814,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opnum_reset = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); - zend_begin_loop(ZEND_FE_FREE, &reset_node); + zend_begin_loop(ZEND_FE_FREE, &reset_node, 0); opnum_fetch = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); @@ -4776,13 +4822,15 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ if (is_this_fetch(value_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); } else if (value_ast->kind == ZEND_AST_VAR && - zend_try_compile_cv(&value_node, value_ast) == SUCCESS) { + zend_try_compile_cv(&value_node, value_ast) == SUCCESS) { SET_NODE(opline->op2, &value_node); } else { opline->op2_type = IS_VAR; opline->op2.var = get_temporary_variable(CG(active_op_array)); GET_NODE(&value_node, opline->op2); - if (by_ref) { + if (value_ast->kind == ZEND_AST_ARRAY) { + zend_compile_list_assign(NULL, value_ast, &value_node, value_ast->attr); + } else if (by_ref) { zend_emit_assign_ref_znode(value_ast, &value_node); } else { zend_emit_assign_znode(value_ast, &value_node); @@ -4921,7 +4969,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); - zend_begin_loop(ZEND_FREE, &expr_node); + zend_begin_loop(ZEND_FREE, &expr_node, 1); case_node.op_type = IS_TMP_VAR; case_node.u.op.var = get_temporary_variable(CG(active_op_array)); @@ -4939,7 +4987,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ jumptable_type == IS_LONG ? ZEND_SWITCH_LONG : ZEND_SWITCH_STRING, &expr_node, &jumptable_op); if (opline->op1_type == IS_CONST) { - zval_copy_ctor(CT_CONSTANT(opline->op1)); + Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1)); } opnum_switch = opline - CG(active_op_array)->opcodes; } @@ -4968,11 +5016,13 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ } else if (expr_node.op_type == IS_CONST && Z_TYPE(expr_node.u.constant) == IS_TRUE) { jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, 0); - } else { - opline = zend_emit_op(NULL, ZEND_CASE, &expr_node, &cond_node); + } else { + opline = zend_emit_op(NULL, + (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) ? ZEND_CASE : ZEND_IS_EQUAL, + &expr_node, &cond_node); SET_NODE(opline->result, &case_node); if (opline->op1_type == IS_CONST) { - zval_copy_ctor(CT_CONSTANT(opline->op1)); + Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1)); } jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0); @@ -4992,7 +5042,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ if (jumptable) { zval *cond_zv = zend_ast_get_zval(cond_ast); zval jmp_target; - ZVAL_LONG(&jmp_target, get_next_op_number(CG(active_op_array))); + ZVAL_LONG(&jmp_target, get_next_op_number(CG(active_op_array))); ZEND_ASSERT(Z_TYPE_P(cond_zv) == jumptable_type); if (Z_TYPE_P(cond_zv) == IS_LONG) { @@ -5030,9 +5080,8 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ opline = get_next_op(CG(active_op_array)); opline->opcode = ZEND_FREE; SET_NODE(opline->op1, &expr_node); - SET_UNUSED(opline->op2); } else if (expr_node.op_type == IS_CONST) { - zval_dtor(&expr_node.u.constant); + zval_ptr_dtor_nogc(&expr_node.u.constant); } efree(jmpnz_opnums); @@ -5097,7 +5146,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ zend_ast_list *classes = zend_ast_get_list(catch_ast->child[0]); zend_ast *var_ast = catch_ast->child[1]; zend_ast *stmt_ast = catch_ast->child[2]; - zval *var_name = zend_ast_get_zval(var_ast); + zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_ast)); zend_bool is_last_catch = (i + 1 == catches->children); uint32_t *jmp_multicatch = safe_emalloc(sizeof(uint32_t), classes->children - 1, 0); @@ -5124,20 +5173,23 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ opline->op1_type = IS_CONST; opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), zend_resolve_class_name_ast(class_ast)); + opline->extended_value = zend_alloc_cache_slot(); - if (zend_string_equals_literal(Z_STR_P(var_name), "this")) { + if (zend_string_equals_literal(var_name, "this")) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); } - opline->op2_type = IS_CV; - opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name))); + opline->result_type = IS_CV; + opline->result.var = lookup_cv(CG(active_op_array), var_name); - opline->result.num = is_last_catch && is_last_class; + if (is_last_catch && is_last_class) { + opline->extended_value |= ZEND_LAST_CATCH; + } if (!is_last_class) { jmp_multicatch[j] = zend_emit_jump(0); opline = &CG(active_op_array)->opcodes[opnum_catch]; - opline->extended_value = get_next_op_number(CG(active_op_array)); + opline->op2.opline_num = get_next_op_number(CG(active_op_array)); } } @@ -5155,7 +5207,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ opline = &CG(active_op_array)->opcodes[opnum_catch]; if (!is_last_catch) { - opline->extended_value = get_next_op_number(CG(active_op_array)); + opline->op2.opline_num = get_next_op_number(CG(active_op_array)); } } @@ -5166,7 +5218,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ if (finally_ast) { zend_loop_var discard_exception; uint32_t opnum_jmp = get_next_op_number(CG(active_op_array)) + 1; - + /* Pop FAST_CALL from unwind stack */ zend_stack_del_top(&CG(loop_var_stack)); @@ -5211,7 +5263,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ /* }}} */ /* Encoding declarations must already be handled during parsing */ -void zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */ +zend_bool zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */ { zend_ast_list *declares = zend_ast_get_list(ast); uint32_t i; @@ -5223,7 +5275,8 @@ void zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */ if (zend_string_equals_literal_ci(name, "encoding")) { if (value_ast->kind != ZEND_AST_ZVAL) { - zend_error_noreturn(E_COMPILE_ERROR, "Encoding must be a literal"); + zend_throw_exception(zend_ce_compile_error, "Encoding must be a literal", 0); + return 0; } if (CG(multibyte)) { @@ -5249,13 +5302,15 @@ void zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */ } } - zend_string_release(encoding_name); + zend_string_release_ex(encoding_name, 0); } else { zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because " "Zend multibyte feature is turned off by settings"); } } } + + return 1; } /* }}} */ @@ -5264,7 +5319,7 @@ static int zend_declare_is_first_statement(zend_ast *ast) /* {{{ */ uint32_t i = 0; zend_ast_list *file_ast = zend_ast_get_list(CG(ast)); - /* Check to see if this declare is preceeded only by declare statements */ + /* Check to see if this declare is preceded only by declare statements */ while (i < file_ast->children) { if (file_ast->child[i] == ast) { return SUCCESS; @@ -5272,7 +5327,7 @@ static int zend_declare_is_first_statement(zend_ast *ast) /* {{{ */ /* Empty statements are not allowed prior to a declare */ return FAILURE; } else if (file_ast->child[i]->kind != ZEND_AST_DECLARE) { - /* declares can only be preceeded by other declares */ + /* declares can only be preceded by other declares */ return FAILURE; } i++; @@ -5302,7 +5357,7 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */ zval value_zv; zend_const_expr_to_zval(&value_zv, value_ast); FC(declarables).ticks = zval_get_long(&value_zv); - zval_dtor(&value_zv); + zval_ptr_dtor_nogc(&value_zv); } else if (zend_string_equals_literal_ci(name, "encoding")) { if (FAILURE == zend_declare_is_first_statement(ast)) { @@ -5391,7 +5446,7 @@ static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info, zend_b if (type != 0) { if ((ast->attr & ZEND_NAME_NOT_FQ) != ZEND_NAME_NOT_FQ) { zend_error_noreturn(E_COMPILE_ERROR, - "Scalar type declaration '%s' must be unqualified", + "Type declaration '%s' must be unqualified", ZSTR_VAL(zend_string_tolower(class_name))); } arg_info->type = ZEND_TYPE_ENCODE(type, allow_null); @@ -5417,7 +5472,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ uint32_t i; zend_op_array *op_array = CG(active_op_array); zend_arg_info *arg_infos; - + if (return_type_ast) { zend_bool allow_null = 0; @@ -5453,7 +5508,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_ast *type_ast = param_ast->child[0]; zend_ast *var_ast = param_ast->child[1]; zend_ast *default_ast = param_ast->child[2]; - zend_string *name = zend_ast_get_str(var_ast); + zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast)); zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0; zend_bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0; @@ -5468,7 +5523,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } var_node.op_type = IS_CV; - var_node.u.op.var = lookup_cv(CG(active_op_array), zend_string_copy(name)); + var_node.u.op.var = lookup_cv(CG(active_op_array), name); if (EX_VAR_TO_NUM(var_node.u.op.var) != i) { zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s", @@ -5519,8 +5574,9 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_bool allow_null; zend_bool has_null_default = default_ast && (Z_TYPE(default_node.u.constant) == IS_NULL - || (Z_TYPE(default_node.u.constant) == IS_CONSTANT - && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0)); + || (Z_TYPE(default_node.u.constant) == IS_CONSTANT_AST + && Z_ASTVAL(default_node.u.constant)->kind == ZEND_AST_CONSTANT + && strcasecmp(ZSTR_VAL(zend_ast_get_constant_name(Z_ASTVAL(default_node.u.constant))), "NULL") == 0)); zend_bool is_explicitly_nullable = (type_ast->attr & ZEND_TYPE_NULLABLE) == ZEND_TYPE_NULLABLE; op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; @@ -5537,19 +5593,19 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) { if (default_ast && !has_null_default && Z_TYPE(default_node.u.constant) != IS_ARRAY - && !Z_CONSTANT(default_node.u.constant) + && Z_TYPE(default_node.u.constant) != IS_CONSTANT_AST ) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with array type can only be an array or NULL"); } } else if (ZEND_TYPE_CODE(arg_info->type) == IS_CALLABLE && default_ast) { - if (!has_null_default && !Z_CONSTANT(default_node.u.constant)) { + if (!has_null_default && Z_TYPE(default_node.u.constant) != IS_CONSTANT_AST) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with callable type can only be NULL"); } } } else { - if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) { + if (default_ast && !has_null_default && Z_TYPE(default_node.u.constant) != IS_CONSTANT_AST) { if (ZEND_TYPE_IS_CLASS(arg_info->type)) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with a class type can only be NULL"); @@ -5560,7 +5616,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ "with a float type can only be float, integer, or NULL"); } break; - + case IS_ITERABLE: if (Z_TYPE(default_node.u.constant) != IS_ARRAY) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " @@ -5572,7 +5628,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with an object type can only be NULL"); break; - + default: if (!ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(arg_info->type), Z_TYPE(default_node.u.constant))) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " @@ -5587,9 +5643,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ /* Allocate cache slot to speed-up run-time class resolution */ if (opline->opcode == ZEND_RECV_INIT) { if (ZEND_TYPE_IS_CLASS(arg_info->type)) { - zend_alloc_cache_slot(opline->op2.constant); - } else { - Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1; + opline->extended_value = zend_alloc_cache_slot(); } } else { if (ZEND_TYPE_IS_CLASS(arg_info->type)) { @@ -5600,15 +5654,13 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } } } else { - if (opline->opcode == ZEND_RECV_INIT) { - Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1; - } else { + if (opline->opcode != ZEND_RECV_INIT) { opline->op2.num = -1; } - } + } } - /* These are assigned at the end to avoid unitialized memory in case of an error */ + /* These are assigned at the end to avoid uninitialized memory in case of an error */ op_array->num_args = list->children; op_array->arg_info = arg_infos; @@ -5620,16 +5672,32 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } /* }}} */ -static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* {{{ */ +static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array, zend_ast *uses_ast) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(uses_ast); uint32_t i; + if (!list->children) { + return; + } + + if (!op_array->static_variables) { + op_array->static_variables = zend_new_array(8); + } + + if (GC_REFCOUNT(op_array->static_variables) > 1) { + if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { + GC_DELREF(op_array->static_variables); + } + op_array->static_variables = zend_array_dup(op_array->static_variables); + } + for (i = 0; i < list->children; ++i) { zend_ast *var_name_ast = list->child[i]; - zend_string *var_name = zend_ast_get_str(var_name_ast); - zend_bool by_ref = var_name_ast->attr; + zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_name_ast)); + uint32_t by_ref = var_name_ast->attr; zend_op *opline; + zval *value; if (zend_string_equals_literal(var_name, "this")) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable"); @@ -5639,10 +5707,16 @@ static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable"); } + value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval)); + if (!value) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use variable $%s twice", ZSTR_VAL(var_name)); + } + opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL); opline->op2_type = IS_CV; - opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(var_name)); - opline->extended_value = by_ref; + opline->op2.var = lookup_cv(CG(active_op_array), var_name); + opline->extended_value = (uint32_t)((char*)value - (char*)op_array->static_variables->arData) | by_ref; } } /* }}} */ @@ -5656,16 +5730,10 @@ void zend_compile_closure_uses(zend_ast *ast) /* {{{ */ for (i = 0; i < list->children; ++i) { zend_ast *var_ast = list->child[i]; zend_string *var_name = zend_ast_get_str(var_ast); - zend_bool by_ref = var_ast->attr; + uint32_t by_ref = var_ast->attr; zval zv; ZVAL_NULL(&zv); - if (op_array->static_variables - && zend_hash_exists(op_array->static_variables, var_name)) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot use variable $%s twice", ZSTR_VAL(var_name)); - } - { int i; for (i = 0; i < op_array->last_var; i++) { @@ -5728,7 +5796,9 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } if (in_interface) { - if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { + if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') { + /* pass */ + } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { if (!is_public || is_static) { zend_error(E_WARNING, "The magic method __call() must have " "public visibility and cannot be static"); @@ -5779,6 +5849,10 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo if (!ce->constructor) { ce->constructor = (zend_function *) op_array; } + } else if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') { + if (!is_static) { + op_array->fn_flags |= ZEND_ACC_ALLOW_STATIC; + } } else if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) { ce->constructor = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) { @@ -5847,7 +5921,7 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } } - zend_string_release(lcname); + zend_string_release_ex(lcname, 0); } /* }}} */ @@ -5879,6 +5953,12 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as zend_error(E_DEPRECATED, "__autoload() is deprecated, use spl_autoload_register() instead"); } + if (zend_string_equals_literal_ci(unqualified_name, "assert")) { + zend_error(E_DEPRECATED, + "Defining a custom assert() function is deprecated, " + "as the function has special semantics"); + } + key = zend_build_runtime_definition_key(lcname, decl->lex_pos); zend_hash_update_ptr(CG(function_table), key, op_array); zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION); @@ -5894,10 +5974,9 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as LITERAL_STR(opline->op1, zend_string_copy(lcname)); /* RTD key is placed after lcname literal in op1 */ zend_add_literal_string(CG(active_op_array), &key); - SET_UNUSED(opline->op2); } - zend_string_release(lcname); + zend_string_release_ex(lcname, 0); } /* }}} */ @@ -5933,7 +6012,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */ } else { zend_begin_func_decl(result, op_array, decl); if (uses_ast) { - zend_compile_closure_binding(result, uses_ast); + zend_compile_closure_binding(result, op_array, uses_ast); } } @@ -6005,7 +6084,7 @@ void zend_compile_prop_decl(zend_ast *ast) /* {{{ */ zend_ast *name_ast = prop_ast->child[0]; zend_ast *value_ast = prop_ast->child[1]; zend_ast *doc_comment_ast = prop_ast->child[2]; - zend_string *name = zend_ast_get_str(name_ast); + zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); zend_string *doc_comment = NULL; zval value_zv; @@ -6031,7 +6110,6 @@ void zend_compile_prop_decl(zend_ast *ast) /* {{{ */ ZVAL_NULL(&value_zv); } - name = zend_new_interned_string_safe(name); zend_declare_property_ex(ce, name, &value_zv, flags, doc_comment); } } @@ -6053,7 +6131,7 @@ void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */ zend_ast *name_ast = const_ast->child[0]; zend_ast *value_ast = const_ast->child[1]; zend_ast *doc_comment_ast = const_ast->child[2]; - zend_string *name = zend_ast_get_str(name_ast); + zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; zval value_zv; @@ -6068,20 +6146,16 @@ void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */ } zend_const_expr_to_zval(&value_zv, value_ast); - - name = zend_new_interned_string_safe(name); zend_declare_class_constant_ex(ce, name, &value_zv, ast->attr, doc_comment); } } /* }}} */ -static zend_trait_method_reference *zend_compile_method_ref(zend_ast *ast) /* {{{ */ +static void zend_compile_method_ref(zend_ast *ast, zend_trait_method_reference *method_ref) /* {{{ */ { zend_ast *class_ast = ast->child[0]; zend_ast *method_ast = ast->child[1]; - zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference)); - method_ref->ce = NULL; method_ref->method_name = zend_string_copy(zend_ast_get_str(method_ast)); if (class_ast) { @@ -6089,25 +6163,6 @@ static zend_trait_method_reference *zend_compile_method_ref(zend_ast *ast) /* {{ } else { method_ref->class_name = NULL; } - - return method_ref; -} -/* }}} */ - -static zend_string **zend_compile_name_list(zend_ast *ast) /* {{{ */ -{ - zend_ast_list *list = zend_ast_get_list(ast); - zend_string **names = safe_emalloc(sizeof(zend_string *), list->children + 1, 0); - uint32_t i; - - for (i = 0; i < list->children; ++i) { - zend_ast *name_ast = list->child[i]; - names[i] = zend_resolve_class_name_ast(name_ast); - } - - names[list->children] = NULL; - - return names; } /* }}} */ @@ -6115,11 +6170,17 @@ static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */ { zend_ast *method_ref_ast = ast->child[0]; zend_ast *insteadof_ast = ast->child[1]; + zend_ast_list *insteadof_list = zend_ast_get_list(insteadof_ast); + uint32_t i; - zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence)); - precedence->trait_method = zend_compile_method_ref(method_ref_ast); - precedence->exclude_from_classes - = (void *) zend_compile_name_list(insteadof_ast); + zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence) + (insteadof_list->children - 1) * sizeof(zend_string*)); + zend_compile_method_ref(method_ref_ast, &precedence->trait_method); + precedence->num_excludes = insteadof_list->children; + + for (i = 0; i < insteadof_list->children; ++i) { + zend_ast *name_ast = insteadof_list->child[i]; + precedence->exclude_class_names[i] = zend_resolve_class_name_ast(name_ast); + } zend_add_to_list(&CG(active_class_entry)->trait_precedences, precedence); } @@ -6142,7 +6203,7 @@ static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */ } alias = emalloc(sizeof(zend_trait_alias)); - alias->trait_method = zend_compile_method_ref(method_ref_ast); + zend_compile_method_ref(method_ref_ast, &alias->trait_method); alias->modifiers = modifiers; if (alias_ast) { @@ -6258,7 +6319,8 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ zend_string *name, *lcname; zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry)); zend_op *opline; - znode declare_node, extends_node; + znode declare_node; + int extends_const; zend_class_entry *original_ce = CG(active_class_entry); znode original_implementing_class = FC(implementing_class); @@ -6311,13 +6373,24 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ } if (extends_ast) { + znode extends_node; + zend_string *extends_name; + if (!zend_is_const_default_class_ref(extends_ast)) { - zend_string *extends_name = zend_ast_get_str(extends_ast); + extends_name = zend_ast_get_str(extends_ast); zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", ZSTR_VAL(extends_name)); } - zend_compile_class_ref(&extends_node, extends_ast, 0); + zend_compile_expr(&extends_node, extends_ast); + if (extends_node.op_type != IS_CONST || Z_TYPE(extends_node.u.constant) != IS_STRING) { + zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name"); + } + extends_name = Z_STR(extends_node.u.constant); + extends_const = zend_add_class_name_literal(CG(active_op_array), + zend_resolve_class_name(extends_name, + extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ)); + zend_string_release_ex(extends_name, 0); ce->ce_flags |= ZEND_ACC_INHERITED; } @@ -6332,7 +6405,8 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ if (decl->flags & ZEND_ACC_ANON_CLASS) { if (extends_ast) { opline->opcode = ZEND_DECLARE_ANON_INHERITED_CLASS; - SET_NODE(opline->op2, &extends_node); + opline->op2_type = IS_CONST; + opline->op2.constant = extends_const; } else { opline->opcode = ZEND_DECLARE_ANON_CLASS; } @@ -6351,10 +6425,10 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ if (extends_ast) { opline->opcode = ZEND_DECLARE_INHERITED_CLASS; - SET_NODE(opline->op2, &extends_node); + opline->op2_type = IS_CONST; + opline->op2.constant = extends_const; } else { opline->opcode = ZEND_DECLARE_CLASS; - SET_UNUSED(opline->op2); } key = zend_build_runtime_definition_key(lcname, decl->lex_pos); @@ -6564,7 +6638,7 @@ void zend_compile_use(zend_ast *ast) /* {{{ */ zend_check_already_in_use(type, old_name, new_name, ns_name); } - zend_string_free(ns_name); + zend_string_efree(ns_name); } else { if (zend_have_seen_symbol(lookup_name, type)) { zend_check_already_in_use(type, old_name, new_name, lookup_name); @@ -6577,8 +6651,8 @@ void zend_compile_use(zend_ast *ast) /* {{{ */ "is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name)); } - zend_string_release(lookup_name); - zend_string_release(new_name); + zend_string_release_ex(lookup_name, 0); + zend_string_release_ex(new_name, 0); } } /* }}} */ @@ -6594,7 +6668,7 @@ void zend_compile_group_use(zend_ast *ast) /* {{{ */ zval *name_zval = zend_ast_get_zval(use->child[0]); zend_string *name = Z_STR_P(name_zval); zend_string *compound_ns = zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name)); - zend_string_release(name); + zend_string_release_ex(name, 0); ZVAL_STR(name_zval, compound_ns); inline_use = zend_ast_create_list(1, ZEND_AST_USE, use); inline_use->attr = ast->attr ? ast->attr : use->attr; @@ -6689,7 +6763,7 @@ void zend_compile_namespace(zend_ast *ast) /* {{{ */ } if (FC(current_namespace)) { - zend_string_release(FC(current_namespace)); + zend_string_release_ex(FC(current_namespace), 0); } if (name_ast) { @@ -6736,7 +6810,7 @@ void zend_compile_halt_compiler(zend_ast *ast) /* {{{ */ ZSTR_VAL(filename), ZSTR_LEN(filename), 0); zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), offset, CONST_CS, 0); - zend_string_release(name); + zend_string_release_ex(name, 0); } /* }}} */ @@ -6937,6 +7011,11 @@ static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */ return 0; } + if (!list->children) { + ZVAL_EMPTY_ARRAY(result); + return 1; + } + array_init_size(result, list->children); for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; @@ -6944,7 +7023,7 @@ static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */ zend_ast *key_ast = elem_ast->child[1]; zval *value = zend_ast_get_zval(value_ast); - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + Z_TRY_ADDREF_P(value); if (key_ast) { zval *key = zend_ast_get_zval(key_ast); @@ -7038,6 +7117,9 @@ void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */ if (right_node.op_type == IS_CONST) { convert_to_string(&right_node.u.constant); } + if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { + opcode = ZEND_FAST_CONCAT; + } } zend_emit_op_tmp(result, opcode, &left_node, &right_node); } while (0); @@ -7180,7 +7262,7 @@ void zend_compile_post_incdec(znode *result, zend_ast *ast) /* {{{ */ zend_ensure_writable_variable(var_ast); if (var_ast->kind == ZEND_AST_PROP) { - zend_op *opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_RW); + zend_op *opline = zend_compile_prop(NULL, var_ast, BP_VAR_RW); opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ; zend_make_tmp_result(result, opline); } else { @@ -7200,7 +7282,7 @@ void zend_compile_pre_incdec(znode *result, zend_ast *ast) /* {{{ */ zend_ensure_writable_variable(var_ast); if (var_ast->kind == ZEND_AST_PROP) { - zend_op *opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW); + zend_op *opline = zend_compile_prop(result, var_ast, BP_VAR_RW); opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ; } else { znode var_node; @@ -7407,8 +7489,10 @@ void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */ zend_compile_expr(&obj_node, obj_ast); if (obj_node.op_type == IS_CONST) { - zend_error_noreturn(E_COMPILE_ERROR, - "instanceof expects an object instance, constant given"); + zend_do_free(&obj_node); + result->op_type = IS_CONST; + ZVAL_FALSE(&result->u.constant); + return; } zend_compile_class_ref_ex(&class_node, class_ast, @@ -7420,6 +7504,7 @@ void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */ opline->op2_type = IS_CONST; opline->op2.constant = zend_add_class_name_literal( CG(active_op_array), Z_STR(class_node.u.constant)); + opline->extended_value = zend_alloc_cache_slot(); } else { SET_NODE(opline->op2, &class_node); } @@ -7476,22 +7561,24 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */ } break; case ZEND_AST_DIM: - opline = zend_compile_dim_common(result, var_ast, BP_VAR_IS); + opline = zend_compile_dim(result, var_ast, BP_VAR_IS); opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ; break; case ZEND_AST_PROP: - opline = zend_compile_prop_common(result, var_ast, BP_VAR_IS); + opline = zend_compile_prop(result, var_ast, BP_VAR_IS); opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ; break; case ZEND_AST_STATIC_PROP: - opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS, 0); + opline = zend_compile_static_prop(result, var_ast, BP_VAR_IS, 0); opline->opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP; break; EMPTY_SWITCH_DEFAULT_CASE() } result->op_type = opline->result_type = IS_TMP_VAR; - opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : ZEND_ISEMPTY; + if (!(ast->kind == ZEND_AST_ISSET)) { + opline->extended_value |= ZEND_ISEMPTY; + } } /* }}} */ @@ -7626,14 +7713,14 @@ void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */ if (last->kind == ZEND_AST_HALT_COMPILER) { result->op_type = IS_CONST; ZVAL_LONG(&result->u.constant, Z_LVAL_P(zend_ast_get_zval(last->child[0]))); - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return; } } if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified)) { result->op_type = IS_CONST; - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return; } @@ -7644,9 +7731,9 @@ void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */ opline->op2.constant = zend_add_const_name_literal( CG(active_op_array), resolved_name, 0); } else { - opline->extended_value = IS_CONSTANT_UNQUALIFIED; + opline->op1.num = IS_CONSTANT_UNQUALIFIED; if (FC(current_namespace)) { - opline->extended_value |= IS_CONSTANT_IN_NAMESPACE; + opline->op1.num |= IS_CONSTANT_IN_NAMESPACE; opline->op2.constant = zend_add_const_name_literal( CG(active_op_array), resolved_name, 1); } else { @@ -7654,7 +7741,7 @@ void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */ CG(active_op_array), resolved_name, 0); } } - zend_alloc_cache_slot(opline->op2.constant); + opline->extended_value = zend_alloc_cache_slot(); } /* }}} */ @@ -7669,7 +7756,7 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, const_ast, 0)) { if (Z_TYPE(result->u.constant) == IS_NULL) { zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL); - opline->extended_value = zend_get_class_fetch_type(zend_ast_get_str(class_ast)); + opline->op1.num = zend_get_class_fetch_type(zend_ast_get_str(class_ast)); } else { result->op_type = IS_CONST; } @@ -7688,10 +7775,10 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ resolved_name = zend_resolve_class_name_ast(class_ast); if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) { result->op_type = IS_CONST; - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return; } - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); } if (const_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(const_ast), "class")) { zend_error_noreturn(E_COMPILE_ERROR, @@ -7706,11 +7793,7 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ zend_set_class_name_op1(opline, &class_node); - if (opline->op1_type == IS_CONST) { - zend_alloc_cache_slot(opline->op2.constant); - } else { - zend_alloc_polymorphic_cache_slot(opline->op2.constant); - } + opline->extended_value = zend_alloc_polymorphic_cache_slot(); } /* }}} */ @@ -7727,14 +7810,14 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast) /* {{{ */ ZVAL_STR_COPY(&result->u.constant, CG(active_class_entry)->name); } else { zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL); - opline->extended_value = fetch_type; + opline->op1.num = fetch_type; } break; case ZEND_FETCH_CLASS_STATIC: case ZEND_FETCH_CLASS_PARENT: { zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL); - opline->extended_value = fetch_type; + opline->op1.num = fetch_type; } break; case ZEND_FETCH_CLASS_DEFAULT: @@ -7754,7 +7837,6 @@ static zend_op *zend_compile_rope_add(znode *result, uint32_t num, znode *elem_n result->op_type = IS_TMP_VAR; result->u.op.var = -1; opline->opcode = ZEND_ROPE_INIT; - SET_UNUSED(opline->op1); } else { opline->opcode = ZEND_ROPE_ADD; SET_NODE(opline->op1, result); @@ -7844,7 +7926,7 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ GET_NODE(result, opline->result); } else { uint32_t var; - uint32_t range = zend_start_live_range_ex(CG(active_op_array), rope_init_lineno); + uint32_t range = zend_start_live_range(CG(active_op_array), rope_init_lineno); init_opline->extended_value = j; opline->opcode = ZEND_ROPE_END; @@ -7856,7 +7938,7 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ i = ((j * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); while (i > 1) { get_temporary_variable(CG(active_op_array)); - i--; + i--; } zend_end_live_range(CG(active_op_array), range, opline - CG(active_op_array)->opcodes, @@ -7892,7 +7974,7 @@ void zend_compile_magic_const(znode *result, zend_ast *ast) /* {{{ */ (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != 0); opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL); - opline->extended_value = ZEND_FETCH_CLASS_SELF; + opline->op1.num = ZEND_FETCH_CLASS_SELF; } /* }}} */ @@ -7917,6 +7999,7 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */ zend_ast *const_ast = ast->child[1]; zend_string *class_name; zend_string *const_name = zend_ast_get_str(const_ast); + zend_string *name; zval result; int fetch_type; @@ -7944,16 +8027,13 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */ zend_string_addref(class_name); } - Z_STR(result) = zend_concat3( + name = zend_concat3( ZSTR_VAL(class_name), ZSTR_LEN(class_name), "::", 2, ZSTR_VAL(const_name), ZSTR_LEN(const_name)); - Z_TYPE_INFO(result) = IS_CONSTANT_EX; - Z_CONST_FLAGS(result) = fetch_type; - zend_ast_destroy(ast); - zend_string_release(class_name); + zend_string_release_ex(class_name, 0); - *ast_ptr = zend_ast_create_zval(&result); + *ast_ptr = zend_ast_create_constant(name, fetch_type | ZEND_FETCH_CLASS_EXCEPTION); } /* }}} */ @@ -7963,25 +8043,21 @@ void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */ zend_ast *name_ast = ast->child[0]; zend_string *orig_name = zend_ast_get_str(name_ast); zend_bool is_fully_qualified; + zval result; + zend_string *resolved_name; - zval result, resolved_name; - ZVAL_STR(&resolved_name, zend_resolve_const_name( - orig_name, name_ast->attr, &is_fully_qualified)); + resolved_name = zend_resolve_const_name( + orig_name, name_ast->attr, &is_fully_qualified); - if (zend_try_ct_eval_const(&result, Z_STR(resolved_name), is_fully_qualified)) { - zend_string_release(Z_STR(resolved_name)); + if (zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) { + zend_string_release_ex(resolved_name, 0); zend_ast_destroy(ast); *ast_ptr = zend_ast_create_zval(&result); return; } - Z_TYPE_INFO(resolved_name) = IS_CONSTANT_EX; - if (!is_fully_qualified) { - Z_CONST_FLAGS(resolved_name) = IS_CONSTANT_UNQUALIFIED; - } - zend_ast_destroy(ast); - *ast_ptr = zend_ast_create_zval(&resolved_name); + *ast_ptr = zend_ast_create_constant(resolved_name, !is_fully_qualified ? IS_CONSTANT_UNQUALIFIED : 0); } /* }}} */ @@ -7994,14 +8070,8 @@ void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */ CG(active_class_entry) && (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != 0); - { - zval const_zv; - Z_STR(const_zv) = zend_string_init("__CLASS__", sizeof("__CLASS__")-1, 0); - Z_TYPE_INFO(const_zv) = IS_CONSTANT_EX | (IS_CONSTANT_CLASS << Z_CONST_FLAGS_SHIFT); - - zend_ast_destroy(ast); - *ast_ptr = zend_ast_create_zval(&const_zv); - } + zend_ast_destroy(ast); + *ast_ptr = zend_ast_create(ZEND_AST_CONSTANT_CLASS); } /* }}} */ @@ -8041,7 +8111,7 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */ if (ast->kind == ZEND_AST_ZVAL) { ZVAL_COPY_VALUE(result, zend_ast_get_zval(ast)); } else { - ZVAL_NEW_AST(result, zend_ast_copy(ast)); + ZVAL_AST(result, zend_ast_copy(ast)); /* destroy the ast here, it might have been replaced */ zend_ast_destroy(ast); } @@ -8361,18 +8431,15 @@ void zend_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { - zend_op *opline; switch (ast->kind) { case ZEND_AST_VAR: zend_compile_simple_var(result, ast, type, 1); return; case ZEND_AST_DIM: - opline = zend_delayed_compile_dim(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_delayed_compile_dim(result, ast, type); return; case ZEND_AST_PROP: - opline = zend_delayed_compile_prop(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_delayed_compile_prop(result, ast, type); return; case ZEND_AST_STATIC_PROP: zend_compile_static_prop(result, ast, type, 1); @@ -8590,11 +8657,11 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified); if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) { - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return; } - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); break; } case ZEND_AST_CLASS_CONST: @@ -8632,11 +8699,11 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ resolved_name = zend_resolve_class_name_ast(class_ast); if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) { - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); return; } - zend_string_release(resolved_name); + zend_string_release_ex(resolved_name, 0); break; } |