summaryrefslogtreecommitdiff
path: root/Zend/zend_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r--Zend/zend_compile.c1215
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;
}