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.c540
1 files changed, 372 insertions, 168 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 10390b04a8..60b9e3e653 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5,7 +5,7 @@
| Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
+ | that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
@@ -107,7 +107,7 @@ ZEND_API zend_executor_globals executor_globals;
static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
{
- if (!IS_INTERNED(property_info->name)) {
+ if (!IS_INTERNED(property_info->name)) {
property_info->name = estrndup(property_info->name, property_info->name_length);
}
if (property_info->doc_comment) {
@@ -118,7 +118,7 @@ static void zend_duplicate_property_info(zend_property_info *property_info) /* {
static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
{
- if (!IS_INTERNED(property_info->name)) {
+ if (!IS_INTERNED(property_info->name)) {
property_info->name = zend_strndup(property_info->name, property_info->name_length);
}
}
@@ -179,6 +179,9 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
CG(context).literals_size = 0;
CG(context).current_brk_cont = -1;
CG(context).backpatch_count = 0;
+ CG(context).nested_calls = 0;
+ CG(context).used_stack = 0;
+ CG(context).in_finally = 0;
CG(context).labels = NULL;
}
/* }}} */
@@ -285,7 +288,7 @@ ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */
static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */
{
- return (op_array->T)++ * ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable));
+ return (zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, (op_array->T)++);
}
/* }}} */
@@ -380,7 +383,7 @@ int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -388,7 +391,7 @@ int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
} else {
ret = zend_add_literal(op_array, zv TSRMLS_CC);
}
-
+
lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
@@ -407,7 +410,7 @@ int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -440,7 +443,7 @@ int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_D
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -474,7 +477,7 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq
int name_len, ns_len;
zval c;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -483,7 +486,7 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq
ret = zend_add_literal(op_array, zv TSRMLS_CC);
}
- /* skip leading '\\' */
+ /* skip leading '\\' */
if (Z_STRVAL_P(zv)[0] == '\\') {
name_len = Z_STRLEN_P(zv) - 1;
name = Z_STRVAL_P(zv) + 1;
@@ -813,7 +816,7 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS
opline.result.var = opline.op1.var;
zend_llist_add_element(fetch_list_ptr, &opline);
}
-
+
init_op(&opline TSRMLS_CC);
opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */
opline.result_type = IS_VAR;
@@ -827,12 +830,12 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline.op2.constant));
- ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline.op2.constant);
}
}
-
+
GET_NODE(result, opline.result);
zend_llist_add_element(fetch_list_ptr, &opline);
@@ -938,7 +941,7 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {
opline->result.var = get_temporary_variable(CG(active_op_array));
opline->op1_type = IS_CONST;
LITERAL_STRINGL(opline->op1,
- CG(active_op_array)->vars[value->u.op.var].name,
+ CG(active_op_array)->vars[value->u.op.var].name,
CG(active_op_array)->vars[value->u.op.var].name_len, 1);
CALCULATE_LITERAL_HASH(opline->op1.constant);
SET_UNUSED(opline->op2);
@@ -1567,7 +1570,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
if (is_method) {
int result;
-
+
lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);
if (IS_INTERNED(lcname)) {
@@ -1619,10 +1622,14 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
}
+ } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
+ }
}
} else {
char *class_lcname;
-
+
class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
/* Improve after RC: cache the lowercase class name */
@@ -1673,8 +1680,12 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
} else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
- }
+ }
CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
+ }
} else if (!(fn_flags & ZEND_ACC_STATIC)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
}
@@ -1724,7 +1735,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
}
{
- /* Push a separator to the switch and foreach stacks */
+ /* Push a separator to the switch stack */
zend_switch_entry switch_entry;
switch_entry.cond.op_type = IS_UNUSED;
@@ -1732,16 +1743,15 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
switch_entry.control_var = 0;
zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
+ }
- {
- /* Foreach stack separator */
- zend_op dummy_opline;
+ {
+ /* Push a separator to the foreach stack */
+ zend_op dummy_opline;
- dummy_opline.result_type = IS_UNUSED;
- dummy_opline.op1_type = IS_UNUSED;
+ dummy_opline.result_type = IS_UNUSED;
- zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
- }
+ zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
}
if (CG(doc_comment)) {
@@ -1804,14 +1814,14 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
if (CG(active_class_entry)) {
zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
} else {
- /* we don't care if the function name is longer, in fact lowercasing only
+ /* we don't care if the function name is longer, in fact lowercasing only
* the beginning of the name speeds up the check process */
name_len = strlen(CG(active_op_array)->function_name);
zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1));
lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) {
zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME);
- }
+ }
}
CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
@@ -1937,7 +1947,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
internal function with short name */
zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
return 1;
- }
+ }
lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
@@ -1946,11 +1956,14 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
efree(lcname);
return 1; /* Dynamic */
- }
+ }
efree(function_name->u.constant.value.str.val);
function_name->u.constant.value.str.val = lcname;
-
+
zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
+ if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
+ }
zend_do_extended_fcall_begin(TSRMLS_C);
return 0;
}
@@ -1979,7 +1992,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
name = CONSTANT(last_op->op2.constant);
if (Z_TYPE(name) != IS_STRING) {
zend_error(E_COMPILE_ERROR, "Method name must be a string");
- }
+ }
if (!IS_INTERNED(Z_STRVAL(name))) {
Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
}
@@ -1989,11 +2002,13 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
}
last_op->opcode = ZEND_INIT_METHOD_CALL;
- SET_UNUSED(last_op->result);
+ last_op->result_type = IS_UNUSED;
+ last_op->result.num = CG(context).nested_calls;
Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
} else {
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
+ opline->result.num = CG(context).nested_calls;
SET_UNUSED(opline->op1);
if (left_bracket->op_type == IS_CONST) {
opline->op2_type = IS_CONST;
@@ -2005,6 +2020,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
}
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
+ if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls;
+ }
zend_do_extended_fcall_begin(TSRMLS_C);
}
/* }}} */
@@ -2032,12 +2050,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
/* In run-time PHP will check for function with full name and
internal function with short name */
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
+ opline->result.num = CG(context).nested_calls;
SET_UNUSED(opline->op1);
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
GET_CACHE_SLOT(opline->op2.constant);
} else {
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
+ opline->result.num = CG(context).nested_calls;
SET_UNUSED(opline->op1);
if (function_name->op_type == IS_CONST) {
opline->op2_type = IS_CONST;
@@ -2049,6 +2069,9 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
}
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
+ if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls;
+ }
zend_do_extended_fcall_begin(TSRMLS_C);
}
/* }}} */
@@ -2104,6 +2127,53 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace
}
/* }}} */
+void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */
+{
+ char *lcname;
+ int lctype;
+ znode constant_name;
+
+ lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len);
+ lctype = zend_get_class_fetch_type(lcname, strlen(lcname));
+ switch (lctype) {
+ case ZEND_FETCH_CLASS_SELF:
+ if (!CG(active_class_entry)) {
+ zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active");
+ }
+ zval_dtor(&class_name->u.constant);
+ class_name->op_type = IS_CONST;
+ ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1);
+ *result = *class_name;
+ break;
+ case ZEND_FETCH_CLASS_STATIC:
+ case ZEND_FETCH_CLASS_PARENT:
+ if (is_static) {
+ zend_error(E_COMPILE_ERROR,
+ "%s::class cannot be used for compile-time class name resolution",
+ lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
+ );
+ }
+ if (!CG(active_class_entry)) {
+ zend_error(E_COMPILE_ERROR,
+ "Cannot access %s::class when no class scope is active",
+ lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
+ );
+ }
+ constant_name.op_type = IS_CONST;
+ ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
+ zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
+ break;
+ case ZEND_FETCH_CLASS_DEFAULT:
+ zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
+ *result = *class_name;
+ break;
+ }
+
+ efree(lcname);
+
+}
+/* }}} */
+
void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */
{
char *compound;
@@ -2126,7 +2196,7 @@ void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_n
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant));
}
- } else {
+ } else {
if (CG(current_import)) {
len = compound - Z_STRVAL(class_name->u.constant);
lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len);
@@ -2397,6 +2467,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
opline->extended_value = class_node.EA ;
}
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
+ opline->result.num = CG(context).nested_calls;
if (class_node.op_type == IS_CONST) {
opline->op1_type = IS_CONST;
opline->op1.constant =
@@ -2418,6 +2489,9 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
}
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
+ if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls;
+ }
zend_do_extended_fcall_begin(TSRMLS_C);
return 1; /* Dynamic */
}
@@ -2438,21 +2512,29 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
opline->opcode = ZEND_DO_FCALL;
SET_NODE(opline->op1, function_name);
+ SET_UNUSED(opline->op2);
+ opline->op2.num = CG(context).nested_calls;
CALCULATE_LITERAL_HASH(opline->op1.constant);
GET_CACHE_SLOT(opline->op1.constant);
} else {
opline->opcode = ZEND_DO_FCALL_BY_NAME;
SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ opline->op2.num = --CG(context).nested_calls;
}
}
opline->result.var = get_temporary_variable(CG(active_op_array));
opline->result_type = IS_VAR;
- GET_NODE(result, opline->result) ;
- SET_UNUSED(opline->op2);
+ GET_NODE(result, opline->result);
zend_stack_del_top(&CG(function_call_stack));
opline->extended_value = Z_LVAL(argument_list->u.constant);
+
+ if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
+ CG(active_op_array)->used_stack = CG(context).used_stack + 1;
+ }
+ CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
}
/* }}} */
@@ -2480,8 +2562,8 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed");
}
return;
- }
-
+ }
+
if (function_ptr) {
if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
@@ -2560,6 +2642,10 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
SET_NODE(opline->op1, param);
opline->op2.opline_num = offset;
SET_UNUSED(opline->op2);
+
+ if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
+ CG(active_op_array)->used_stack = CG(context).used_stack;
+ }
}
/* }}} */
@@ -2576,7 +2662,7 @@ static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRML
opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
SET_NODE(opline->op1, &switch_entry->cond);
SET_UNUSED(opline->op2);
- opline->extended_value = 0;
+
return 0;
}
/* }}} */
@@ -2586,7 +2672,7 @@ static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /*
zend_op *opline;
/* If we reach the separator then stop applying the stack */
- if (foreach_copy->result_type == IS_UNUSED && foreach_copy->op1_type == IS_UNUSED) {
+ if (foreach_copy->result_type == IS_UNUSED) {
return 1;
}
@@ -2595,16 +2681,6 @@ static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /*
opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
COPY_NODE(opline->op1, foreach_copy->result);
SET_UNUSED(opline->op2);
- opline->extended_value = 1;
-
- if (foreach_copy->op1_type != IS_UNUSED) {
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
-
- opline->opcode = (foreach_copy->op1_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
- COPY_NODE(opline->op1, foreach_copy->op1);
- SET_UNUSED(opline->op2);
- opline->extended_value = 0;
- }
return 0;
}
@@ -2614,9 +2690,12 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
{
zend_op *opline;
int start_op_number, end_op_number;
+ zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+
+ /* The error for use of return inside a generator is thrown in pass_two. */
if (do_end_vparse) {
- if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(expr)) {
+ if (returns_reference && !zend_is_function_or_method_call(expr)) {
zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
} else {
zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);
@@ -2639,9 +2718,16 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
start_op_number++;
}
+ if (CG(context).in_finally) {
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_DISCARD_EXCEPTION;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ }
+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) ? ZEND_RETURN_BY_REF : ZEND_RETURN;
+ opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
if (expr) {
SET_NODE(opline->op1, expr);
@@ -2658,12 +2744,59 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
}
/* }}} */
+void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC) /* {{{ */
+{
+ zend_op *opline;
+
+ if (!CG(active_op_array)->function_name) {
+ zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
+ }
+
+ CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
+
+ if (is_variable) {
+ if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(value)) {
+ zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
+ } else {
+ zend_do_end_variable_parse(value, BP_VAR_R, 0 TSRMLS_CC);
+ }
+ }
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ opline->opcode = ZEND_YIELD;
+
+ if (value) {
+ SET_NODE(opline->op1, value);
+
+ if (is_variable && zend_is_function_or_method_call(value)) {
+ opline->extended_value = ZEND_RETURNS_FUNCTION;
+ }
+ } else {
+ SET_UNUSED(opline->op1);
+ }
+
+ if (key) {
+ SET_NODE(opline->op2, key);
+ } else {
+ SET_UNUSED(opline->op2);
+ }
+
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = get_temporary_variable(CG(active_op_array));
+ GET_NODE(result, opline->result);
+}
+/* }}} */
+
static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
{
int try_catch_offset = CG(active_op_array)->last_try_catch++;
CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
+ CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0;
+ CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
+ CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
return try_catch_offset;
}
/* }}} */
@@ -2680,7 +2813,7 @@ void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */
}
/* }}} */
-void zend_initialize_try_catch_element(const znode *try_token TSRMLS_DC) /* {{{ */
+void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */
{
int jmp_op_number = get_next_op_number(CG(active_op_array));
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -2697,7 +2830,7 @@ void zend_initialize_try_catch_element(const znode *try_token TSRMLS_DC) /* {{{
zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
- zend_add_catch_element(try_token->u.op.opline_num, get_next_op_number(CG(active_op_array)) TSRMLS_CC);
+ catch_token->EA = get_next_op_number(CG(active_op_array));
}
/* }}} */
@@ -2723,7 +2856,29 @@ void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */
}
/* }}} */
-void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
+void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */
+{
+ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
+ /* call the the "finally" block */
+ opline->opcode = ZEND_FAST_CALL;
+ SET_UNUSED(opline->op1);
+ opline->op1.opline_num = finally_token->u.op.opline_num + 1;
+ SET_UNUSED(opline->op2);
+ /* jump to code after the "finally" block,
+ * the actual jump address is going to be set in zend_do_end_finally()
+ */
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_JMP;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ CG(context).in_finally++;
+}
+/* }}} */
+
+void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
{
long catch_op_number;
zend_op *opline;
@@ -2751,11 +2906,11 @@ void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var,
Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
opline->result.num = 0; /* 1 means it's the last catch in the block */
- try_token->u.op.opline_num = catch_op_number;
+ catch_token->u.op.opline_num = catch_op_number;
}
/* }}} */
-void zend_do_end_catch(const znode *try_token TSRMLS_DC) /* {{{ */
+void zend_do_end_catch(znode *catch_token TSRMLS_DC) /* {{{ */
{
int jmp_op_number = get_next_op_number(CG(active_op_array));
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -2769,7 +2924,38 @@ void zend_do_end_catch(const znode *try_token TSRMLS_DC) /* {{{ */
zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
- CG(active_op_array)->opcodes[try_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->opcodes[catch_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
+}
+/* }}} */
+
+void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ */ {
+ if (catch_token->op_type != IS_UNUSED) {
+ zend_add_catch_element(try_token->u.op.opline_num, catch_token->EA TSRMLS_CC);
+ }
+}
+/* }}} */
+
+void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */
+{
+ if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
+ zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
+ }
+ if (finally_token->op_type != IS_UNUSED) {
+ zend_op *opline;
+
+ CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
+ CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->has_finally_block = 1;
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_FAST_RET;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
+
+ CG(context).in_finally--;
+ }
}
/* }}} */
@@ -2876,7 +3062,7 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
- if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
+ if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
if (function->common.fn_flags & ZEND_ACC_CTOR) {
/* inherit parent's constructor */
@@ -3015,8 +3201,8 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
return 0;
}
}
- }
- }
+ }
+ }
if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
/* Incompatible type hint */
return 0;
@@ -3045,7 +3231,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
buf = erealloc(buf, length); \
}
-static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
+static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
{
char *offset, *buf;
zend_uint length = 1024;
@@ -3062,7 +3248,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
*(offset++) = ':';
*(offset++) = ':';
}
-
+
{
size_t name_len = strlen(fptr->common.function_name);
REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
@@ -3103,7 +3289,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
offset += type_name_len;
*(offset++) = ' ';
}
-
+
if (arg_info->pass_by_reference) {
*(offset++) = '&';
}
@@ -3205,7 +3391,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
*offset = '\0';
return buf;
-}
+}
/* }}} */
static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
@@ -3217,7 +3403,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
&& parent->common.fn_flags & ZEND_ACC_ABSTRACT
&& parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
&& child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
- zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
+ zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
parent->common.scope->name,
child->common.function_name,
child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);
@@ -3257,7 +3443,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
}
if (parent_flags & ZEND_ACC_PRIVATE) {
- child->common.prototype = NULL;
+ child->common.prototype = NULL;
} else if (parent_flags & ZEND_ACC_ABSTRACT) {
child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
child->common.prototype = parent;
@@ -3268,12 +3454,12 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
- zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
+ zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
}
} else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
- zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
+ zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
efree(method_prototype);
}
}
@@ -3292,9 +3478,9 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f
}
return 1; /* method doesn't exist in child, copy from parent */
}
-
+
do_inheritance_check_on_method(child, parent TSRMLS_CC);
-
+
return 0;
}
/* }}} */
@@ -3325,7 +3511,7 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
(parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,
(child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
-
+
}
if(parent_info->flags & ZEND_ACC_CHANGED) {
@@ -3591,10 +3777,10 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
}
}
ce->interfaces[ce->num_interfaces++] = iface;
-
+
zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
-
+
do_implement_interface(ce, iface TSRMLS_CC);
zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
}
@@ -3634,10 +3820,10 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
{
zend_uint fn_flags = fn->common.scope->ce_flags;
zend_uint other_flags = other_fn->common.scope->ce_flags;
-
+
return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
&& ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
- && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
+ && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
(other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
}
/* }}} */
@@ -3650,7 +3836,7 @@ static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint
if (ce->constructor) {
zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
}
- ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
+ ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
} else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME, mname_len)) {
ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
} else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) {
@@ -3787,7 +3973,7 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
ce = va_arg(args, zend_class_entry*);
overriden = va_arg(args, HashTable**);
exclude_table = va_arg(args, HashTable*);
-
+
fnname_len = hash_key->nKeyLength - 1;
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
@@ -3801,9 +3987,9 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
&& alias->trait_method->mname_len == fnname_len
&& (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) {
fn_copy = *fn;
-
+
/* if it is 0, no modifieres has been changed */
- if (alias->modifiers) {
+ if (alias->modifiers) {
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
}
@@ -3908,7 +4094,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
cur_method_ref->ce->name,
cur_method_ref->method_name);
}
-
+
/** With the other traits, we are more permissive.
We do not give errors for those. This allows to be more
defensive in such definitions.
@@ -3922,20 +4108,20 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
- }
+ }
zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
/* make sure that the trait method is not from a class mentioned in
exclude_from_classes, for consistency */
if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
zend_error(E_COMPILE_ERROR,
- "Inconsistent insteadof definition. "
+ "Inconsistent insteadof definition. "
"The method %s is to be used from %s, but %s is also on the exclude list",
cur_method_ref->method_name,
cur_precedence->trait_method->ce->name,
cur_precedence->trait_method->ce->name);
}
-
+
efree(class_name);
j++;
}
@@ -3975,7 +4161,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
{
size_t i = 0, j;
-
+
if (!precedences) {
return;
}
@@ -3986,7 +4172,7 @@ static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_tra
if (precedences[i]->exclude_from_classes[j] == trait) {
zend_uint lcname_len = precedences[i]->trait_method->mname_len;
char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len);
-
+
if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) {
efree(lcname);
zend_error(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name, trait->name);
@@ -4023,7 +4209,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{
zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
}
}
-
+
zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
if (overriden) {
@@ -4061,7 +4247,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
const char* class_name_unused;
zend_bool not_compatible;
zval* prop_value;
- char* doc_comment;
+ char* doc_comment;
zend_uint flags;
/* In the following steps the properties are inserted into the property table
@@ -4083,18 +4269,17 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
prop_name_length = property_info->name_length;
} else {
/* for private and protected we need to unmangle the names */
- zend_unmangle_property_name(property_info->name, property_info->name_length,
- &class_name_unused, &prop_name);
- prop_name_length = strlen(prop_name);
+ zend_unmangle_property_name_ex(property_info->name, property_info->name_length,
+ &class_name_unused, &prop_name, &prop_name_length);
prop_hash = zend_get_hash_value(prop_name, prop_name_length + 1);
}
/* next: check for conflicts with current class */
if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
- if (coliding_prop->flags & ZEND_ACC_SHADOW) {
+ if (coliding_prop->flags & ZEND_ACC_SHADOW) {
zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
flags |= ZEND_ACC_CHANGED;
- } else {
+ } else {
if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
== (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
/* flags are identical, now the value needs to be checked */
@@ -4115,14 +4300,14 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
}
if (not_compatible) {
- zend_error(E_COMPILE_ERROR,
+ zend_error(E_COMPILE_ERROR,
"%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
property_info->ce->name,
prop_name,
ce->name);
} else {
- zend_error(E_STRICT,
+ zend_error(E_STRICT,
"%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
property_info->ce->name,
@@ -4142,8 +4327,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
Z_ADDREF_P(prop_value);
doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
- zend_declare_property_ex(ce, prop_name, prop_name_length,
- prop_value, flags,
+ zend_declare_property_ex(ce, prop_name, prop_name_length,
+ prop_value, flags,
doc_comment, property_info->doc_comment_len TSRMLS_CC);
}
}
@@ -4155,7 +4340,7 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce
int i = 0;
zend_trait_alias* cur_alias;
char* lc_method_name;
-
+
if (ce->trait_aliases) {
while (ce->trait_aliases[i]) {
cur_alias = ce->trait_aliases[i];
@@ -4176,7 +4361,7 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce
we check against it and abort.
2) it is just a plain old inconsitency/typo/bug
as in the case where alias is set. */
-
+
lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name,
cur_alias->trait_method->mname_len);
if (zend_hash_exists(&ce->function_table,
@@ -4213,7 +4398,7 @@ ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
/* first care about all methods to be flattened into the class */
zend_do_traits_method_binding(ce TSRMLS_CC);
-
+
/* Aliases which have not been applied indicate typos/bugs. */
zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
@@ -4222,7 +4407,7 @@ ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
/* verify that all abstract methods from traits have been implemented */
zend_verify_abstract_class(ce TSRMLS_CC);
-
+
/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
@@ -4272,7 +4457,7 @@ void zend_prepare_reference(znode *result, znode *class_name, znode *method_name
zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
method_ref->ce = NULL;
- /* REM: There should not be a need for copying,
+ /* REM: There should not be a need for copying,
zend_do_begin_class_declaration is also just using that string */
if (class_name) {
zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
@@ -4316,8 +4501,6 @@ void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alia
} else {
trait_alias->alias = NULL;
}
- trait_alias->function = NULL;
-
zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
}
/* }}} */
@@ -4330,8 +4513,6 @@ void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS
trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.op.ptr;
- trait_precedence->function = NULL;
-
zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
}
/* }}} */
@@ -4850,7 +5031,7 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name
build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);
opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
-
+
opline->op2_type = IS_CONST;
if (doing_inheritance) {
@@ -4867,7 +5048,7 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name
LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0);
CALCULATE_LITERAL_HASH(opline->op2.constant);
-
+
zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry;
@@ -4918,7 +5099,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
}
ce->info.user.line_end = zend_get_compiled_lineno(TSRMLS_C);
-
+
/* Check for traits and proceed like with interfaces.
* The only difference will be a combined handling of them in the end.
* Thus, we need another opcode here. */
@@ -4943,7 +5124,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
}
}
/* Inherit interfaces; reset number to zero, we need it for above check and
- * will restore it during actual implementation.
+ * will restore it during actual implementation.
* The ZEND_ACC_IMPLEMENT_INTERFACES flag disables double call to
* zend_verify_abstract_class() */
if (ce->num_interfaces > 0) {
@@ -5044,7 +5225,7 @@ static int zend_strnlen(const char* s, int maxlen) /* {{{ */
}
/* }}} */
-ZEND_API int zend_unmangle_property_name(const char *mangled_property, int len, const char **class_name, const char **prop_name) /* {{{ */
+ZEND_API int zend_unmangle_property_name_ex(const char *mangled_property, int len, const char **class_name, const char **prop_name, int *prop_len) /* {{{ */
{
int class_name_len;
@@ -5052,22 +5233,34 @@ ZEND_API int zend_unmangle_property_name(const char *mangled_property, int len,
if (mangled_property[0]!=0) {
*prop_name = mangled_property;
+ if (prop_len) {
+ *prop_len = len;
+ }
return SUCCESS;
}
if (len < 3 || mangled_property[1]==0) {
zend_error(E_NOTICE, "Illegal member variable name");
*prop_name = mangled_property;
+ if (prop_len) {
+ *prop_len = len;
+ }
return FAILURE;
}
- class_name_len = zend_strnlen(mangled_property+1, --len - 1) + 1;
+ class_name_len = zend_strnlen(mangled_property + 1, --len - 1) + 1;
if (class_name_len >= len || mangled_property[class_name_len]!=0) {
zend_error(E_NOTICE, "Corrupt member variable name");
*prop_name = mangled_property;
+ if (prop_len) {
+ *prop_len = len + 1;
+ }
return FAILURE;
}
- *class_name = mangled_property+1;
- *prop_name = (*class_name)+class_name_len;
+ *class_name = mangled_property + 1;
+ *prop_name = (*class_name) + class_name_len;
+ if (prop_len) {
+ *prop_len = len - class_name_len;
+ }
return SUCCESS;
}
/* }}} */
@@ -5133,7 +5326,7 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
ALLOC_ZVAL(property);
*property = value->u.constant;
-
+
cname = zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, 0 TSRMLS_CC);
if (IS_INTERNED(cname)) {
@@ -5146,7 +5339,7 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
}
FREE_PNODE(var_name);
-
+
if (CG(doc_comment)) {
efree(CG(doc_comment));
CG(doc_comment) = NULL;
@@ -5235,17 +5428,17 @@ void zend_do_halt_compiler_register(TSRMLS_D) /* {{{ */
char *name, *cfilename;
char haltoff[] = "__COMPILER_HALT_OFFSET__";
int len, clen;
-
+
if (CG(has_bracketed_namespaces) && CG(in_namespace)) {
zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope");
}
-
+
cfilename = zend_get_compiled_filename(TSRMLS_C);
clen = strlen(cfilename);
zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
zend_register_long_constant(name, len+1, zend_get_scanned_file_offset(TSRMLS_C), CONST_CS, 0 TSRMLS_CC);
pefree(name, 0);
-
+
if (CG(in_namespace)) {
zend_do_end_namespace(TSRMLS_C);
}
@@ -5278,12 +5471,16 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /*
new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_NEW;
+ opline->extended_value = CG(context).nested_calls;
opline->result_type = IS_VAR;
opline->result.var = get_temporary_variable(CG(active_op_array));
SET_NODE(opline->op1, class_type);
SET_UNUSED(opline->op2);
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
+ if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls;
+ }
}
/* }}} */
@@ -5318,7 +5515,7 @@ static zend_constant* zend_get_ct_const(const zval *const_name, int all_internal
}
} else if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)+1, (void **) &c) == FAILURE) {
char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name), Z_STRLEN_P(const_name));
-
+
if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name)+1, (void **) &c)==SUCCESS) {
if ((c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
efree(lookup_name);
@@ -5371,7 +5568,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
case ZEND_CT:
/* this is a class constant */
type = zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant));
-
+
if (ZEND_FETCH_CLASS_STATIC == type) {
zend_error(E_ERROR, "\"static::\" is not allowed in compile-time constants");
} else if (ZEND_FETCH_CLASS_DEFAULT == type) {
@@ -5435,7 +5632,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
-
+
if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) {
break;
}
@@ -5451,7 +5648,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
/* the name is unambiguous */
opline->extended_value = 0;
opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
- } else {
+ } else {
opline->extended_value = IS_CONSTANT_UNQUALIFIED;
if (CG(current_namespace)) {
opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
@@ -5495,7 +5692,15 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
GET_CACHE_SLOT(opline->op1.constant);
opline->extended_value = 1;
SET_UNUSED(opline->op2);
+ opline->op2.num = CG(context).nested_calls;
GET_NODE(result, opline->result);
+
+ if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
+ CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
+ }
+ if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) {
+ CG(active_op_array)->used_stack = CG(context).used_stack + 2;
+ }
}
/* }}} */
@@ -5518,7 +5723,7 @@ void zend_do_init_array(znode *result, const znode *expr, const znode *offset, z
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline->op2.constant));
- ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline->op2.constant);
}
@@ -5550,7 +5755,7 @@ void zend_do_add_array_element(znode *result, const znode *expr, const znode *of
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline->op2.constant));
- ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline->op2.constant);
}
@@ -5810,7 +6015,7 @@ void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC)
Z_TYPE(value.u.constant) |= is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
Z_SET_REFCOUNT_P(&value.u.constant, 1);
Z_UNSET_ISREF_P(&value.u.constant);
-
+
zend_do_fetch_static_variable(varname, &value, is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC);
}
/* }}} */
@@ -5940,7 +6145,16 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC
zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC);
- zend_check_writable_variable(variable);
+ if (zend_is_function_or_method_call(variable)) {
+ if (type == ZEND_ISEMPTY) {
+ /* empty(func()) can be transformed to !func() */
+ zend_do_unary_op(ZEND_BOOL_NOT, result, variable TSRMLS_CC);
+ } else {
+ zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of a function call (you can use \"null !== func()\" instead)");
+ }
+
+ return;
+ }
if (variable->op_type == IS_CV) {
last_op = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -6003,7 +6217,6 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
{
zend_op *opline;
zend_bool is_variable;
- zend_bool push_container = 0;
zend_op dummy_opline;
if (variable) {
@@ -6015,14 +6228,6 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
/* save the location of FETCH_W instruction(s) */
open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC);
- if (CG(active_op_array)->last > 0 &&
- CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_FETCH_OBJ_W) {
- /* Only lock the container if we are fetching from a real container and not $this */
- if (CG(active_op_array)->opcodes[CG(active_op_array)->last-1].op1_type == IS_VAR) {
- CG(active_op_array)->opcodes[CG(active_op_array)->last-1].extended_value |= ZEND_FETCH_ADD_LOCK;
- push_container = 1;
- }
- }
} else {
is_variable = 0;
open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
@@ -6042,11 +6247,6 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0;
COPY_NODE(dummy_opline.result, opline->result);
- if (push_container) {
- COPY_NODE(dummy_opline.op1, CG(active_op_array)->opcodes[CG(active_op_array)->last-2].op1);
- } else {
- dummy_opline.op1_type = IS_UNUSED;
- }
zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
/* save the location of FE_FETCH */
@@ -6087,20 +6287,22 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token
opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
}
- if ((key->op_type != IS_UNUSED) && (key->EA & ZEND_PARSED_REFERENCE_VARIABLE)) {
- zend_error(E_COMPILE_ERROR, "Key element cannot be a reference");
+ if ((key->op_type != IS_UNUSED)) {
+ if (key->EA & ZEND_PARSED_REFERENCE_VARIABLE) {
+ zend_error(E_COMPILE_ERROR, "Key element cannot be a reference");
+ }
+ if (key->EA & ZEND_PARSED_LIST_EXPR) {
+ zend_error(E_COMPILE_ERROR, "Cannot use list as key element");
+ }
}
if (value->EA & ZEND_PARSED_REFERENCE_VARIABLE) {
assign_by_ref = 1;
- if (!(opline-1)->extended_value) {
- zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression");
- }
+
/* Mark extended_value for assign-by-reference */
opline->extended_value |= ZEND_FE_FETCH_BYREF;
CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE;
} else {
- zend_op *foreach_copy;
zend_op *fetch = &CG(active_op_array)->opcodes[foreach_token->u.op.opline_num];
zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.op.opline_num];
@@ -6117,20 +6319,25 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token
fetch->opcode -= 3; /* FETCH_W -> FETCH_R */
}
}
- /* prevent double SWITCH_FREE */
- zend_stack_top(&CG(foreach_copy_stack), (void **) &foreach_copy);
- foreach_copy->op1_type = IS_UNUSED;
}
GET_NODE(&value_node, opline->result);
- if (assign_by_ref) {
- zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
- /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */
- zend_do_assign_ref(NULL, value, &value_node TSRMLS_CC);
- } else {
- zend_do_assign(&dummy, value, &value_node TSRMLS_CC);
+ if (value->EA & ZEND_PARSED_LIST_EXPR) {
+ if (!CG(list_llist).head) {
+ zend_error(E_COMPILE_ERROR, "Cannot use empty list");
+ }
+ zend_do_list_end(&dummy, &value_node TSRMLS_CC);
zend_do_free(&dummy TSRMLS_CC);
+ } else {
+ if (assign_by_ref) {
+ zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
+ /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */
+ zend_do_assign_ref(NULL, value, &value_node TSRMLS_CC);
+ } else {
+ zend_do_assign(&dummy, value, &value_node TSRMLS_CC);
+ zend_do_free(&dummy TSRMLS_CC);
+ }
}
if (key->op_type != IS_UNUSED) {
@@ -6306,7 +6513,7 @@ void zend_do_jmp_set(const znode *value, znode *jmp_token, znode *colon_token TS
opline->result.var = get_temporary_variable(CG(active_op_array));
SET_NODE(opline->op1, value);
SET_UNUSED(opline->op2);
-
+
GET_NODE(colon_token, opline->result);
jmp_token->u.op.opline_num = op_number;
@@ -6335,11 +6542,11 @@ void zend_do_jmp_set_else(znode *result, const znode *false_value, const znode *
opline->extended_value = 0;
SET_NODE(opline->op1, false_value);
SET_UNUSED(opline->op2);
-
+
GET_NODE(result, opline->result);
CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
-
+
DEC_BPC(CG(active_op_array));
}
/* }}} */
@@ -6552,16 +6759,13 @@ again:
CG(increment_lineno) = 1;
}
if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
- goto again;
+ goto again;
}
retval = ';'; /* implicit ; */
break;
case T_OPEN_TAG_WITH_ECHO:
retval = T_ECHO;
break;
- case T_END_HEREDOC:
- efree(Z_STRVAL(zendlval->u.constant));
- break;
}
INIT_PZVAL(&zendlval->u.constant);
@@ -6645,13 +6849,13 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
int zend_get_class_fetch_type(const char *class_name, uint class_name_len) /* {{{ */
{
if ((class_name_len == sizeof("self")-1) &&
- !memcmp(class_name, "self", sizeof("self")-1)) {
- return ZEND_FETCH_CLASS_SELF;
+ !strncasecmp(class_name, "self", sizeof("self")-1)) {
+ return ZEND_FETCH_CLASS_SELF;
} else if ((class_name_len == sizeof("parent")-1) &&
- !memcmp(class_name, "parent", sizeof("parent")-1)) {
+ !strncasecmp(class_name, "parent", sizeof("parent")-1)) {
return ZEND_FETCH_CLASS_PARENT;
} else if ((class_name_len == sizeof("static")-1) &&
- !memcmp(class_name, "static", sizeof("static")-1)) {
+ !strncasecmp(class_name, "static", sizeof("static")-1)) {
return ZEND_FETCH_CLASS_STATIC;
} else {
return ZEND_FETCH_CLASS_DEFAULT;
@@ -6764,7 +6968,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC
efree(CG(current_import));
CG(current_import) = NULL;
}
-
+
if (CG(doc_comment)) {
efree(CG(doc_comment));
CG(doc_comment) = NULL;
@@ -6936,7 +7140,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
len_adjust += 2;
if (2 == len) {
/* Return "c:" on Win32 for dirname("c:").
- * It would be more consistent to return "c:."
+ * It would be more consistent to return "c:."
* but that would require making the string *longer*.
*/
return len;