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.c278
1 files changed, 195 insertions, 83 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index c5c9f1f475..7210cb4bab 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -62,20 +62,15 @@ typedef struct _zend_loop_var {
} u;
} zend_loop_var;
-static inline uint32_t zend_alloc_cache_slot(void) {
+static inline uint32_t zend_alloc_cache_slots(unsigned count) {
zend_op_array *op_array = CG(active_op_array);
uint32_t ret = op_array->cache_size;
- op_array->cache_size += sizeof(void*);
+ op_array->cache_size += count * sizeof(void*);
return ret;
}
-#define POLYMORPHIC_CACHE_SLOT_SIZE 2
-
-static inline uint32_t zend_alloc_polymorphic_cache_slot(void) {
- zend_op_array *op_array = CG(active_op_array);
- uint32_t ret = op_array->cache_size;
- op_array->cache_size += POLYMORPHIC_CACHE_SLOT_SIZE * sizeof(void*);
- return ret;
+static inline uint32_t zend_alloc_cache_slot(void) {
+ return zend_alloc_cache_slots(1);
}
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
@@ -1605,6 +1600,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
ce->default_properties_count = 0;
ce->default_static_members_count = 0;
+ ce->properties_info_table = NULL;
if (nullify_handlers) {
ce->constructor = NULL;
@@ -2475,7 +2471,7 @@ 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) /* {{{ */
+static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */
{
if (is_this_fetch(ast)) {
zend_op *opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL);
@@ -2483,9 +2479,11 @@ static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type,
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
}
+ return opline;
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
- zend_compile_simple_var_no_cv(result, ast, type, delayed);
+ return zend_compile_simple_var_no_cv(result, ast, type, delayed);
}
+ return NULL;
}
/* }}} */
@@ -2503,7 +2501,7 @@ 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);
+zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, zend_bool by_ref);
void zend_compile_assign(znode *result, zend_ast *ast);
static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
@@ -2524,7 +2522,11 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
znode var_node, dim_node;
- zend_delayed_compile_var(&var_node, var_ast, type);
+ opline = zend_delayed_compile_var(&var_node, var_ast, type, 0);
+ if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
+ opline->extended_value |= ZEND_FETCH_DIM_WRITE;
+ }
+
zend_separate_if_call_and_write(&var_node, var_ast, type);
if (dim_ast == NULL) {
@@ -2568,7 +2570,11 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
if (is_this_fetch(obj_ast)) {
obj_node.op_type = IS_UNUSED;
} else {
- zend_delayed_compile_var(&obj_node, obj_ast, type);
+ opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
+ if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
+ opline->extended_value |= ZEND_FETCH_OBJ_WRITE;
+ }
+
zend_separate_if_call_and_write(&obj_node, obj_ast, type);
}
zend_compile_expr(&prop_node, prop_ast);
@@ -2576,7 +2582,7 @@ 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));
- opline->extended_value = zend_alloc_polymorphic_cache_slot();
+ opline->extended_value = zend_alloc_cache_slots(3);
}
zend_adjust_for_fetch_type(opline, result, type);
@@ -2584,15 +2590,18 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
}
/* }}} */
-static zend_op *zend_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
+static zend_op *zend_compile_prop(znode *result, zend_ast *ast, uint32_t type, int by_ref) /* {{{ */
{
uint32_t offset = zend_delayed_compile_begin();
- zend_delayed_compile_prop(result, ast, type);
+ zend_op *opline = zend_delayed_compile_prop(result, ast, type);
+ if (by_ref) { /* shared with cache_slot */
+ opline->extended_value |= ZEND_FETCH_REF;
+ }
return zend_delayed_compile_end(offset);
}
/* }}} */
-zend_op *zend_compile_static_prop(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 by_ref, int delayed) /* {{{ */
{
zend_ast *class_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
@@ -2611,7 +2620,7 @@ zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, i
}
if (opline->op1_type == IS_CONST) {
convert_to_string(CT_CONSTANT(opline->op1));
- opline->extended_value = zend_alloc_polymorphic_cache_slot();
+ opline->extended_value = zend_alloc_cache_slots(3);
}
if (class_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
@@ -2624,6 +2633,10 @@ zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, i
SET_NODE(opline->op2, &class_node);
}
+ if (by_ref && (type == BP_VAR_W || type == BP_VAR_FUNC_ARG)) { /* shared with cache_slot */
+ opline->extended_value |= ZEND_FETCH_REF;
+ }
+
zend_adjust_for_fetch_type(opline, result, type);
return opline;
}
@@ -2854,13 +2867,22 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
switch (var_ast->kind) {
case ZEND_AST_VAR:
- case ZEND_AST_STATIC_PROP:
offset = zend_delayed_compile_begin();
- zend_delayed_compile_var(&var_node, var_ast, BP_VAR_W);
+ zend_delayed_compile_var(&var_node, var_ast, BP_VAR_W, 0);
zend_compile_expr(&expr_node, expr_ast);
zend_delayed_compile_end(offset);
zend_emit_op(result, ZEND_ASSIGN, &var_node, &expr_node);
return;
+ case ZEND_AST_STATIC_PROP:
+ offset = zend_delayed_compile_begin();
+ zend_delayed_compile_var(result, var_ast, BP_VAR_W, 0);
+ zend_compile_expr(&expr_node, expr_ast);
+
+ opline = zend_delayed_compile_end(offset);
+ opline->opcode = ZEND_ASSIGN_STATIC_PROP;
+
+ zend_emit_op_data(&expr_node);
+ return;
case ZEND_AST_DIM:
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
@@ -2901,7 +2923,7 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
"Cannot assign reference to non referencable value");
}
- zend_compile_var(&expr_node, expr_ast, BP_VAR_W);
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
/* 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
@@ -2945,8 +2967,8 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
zend_ensure_writable_variable(target_ast);
offset = zend_delayed_compile_begin();
- zend_delayed_compile_var(&target_node, target_ast, BP_VAR_W);
- zend_compile_var(&source_node, source_ast, BP_VAR_W);
+ zend_delayed_compile_var(&target_node, target_ast, BP_VAR_W, 1);
+ zend_compile_var(&source_node, source_ast, BP_VAR_W, 1);
if ((target_ast->kind != ZEND_AST_VAR
|| target_ast->child[0]->kind != ZEND_AST_ZVAL)
@@ -2960,16 +2982,33 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
zend_emit_op(&source_node, ZEND_MAKE_REF, &source_node, NULL);
}
- zend_delayed_compile_end(offset);
+ opline = zend_delayed_compile_end(offset);
if (source_node.op_type != IS_VAR && zend_is_call(source_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
}
- opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node);
+ if (opline && opline->opcode == ZEND_FETCH_OBJ_W) {
+ opline->opcode = ZEND_ASSIGN_OBJ_REF;
+ opline->extended_value &= ~ZEND_FETCH_REF;
+ zend_emit_op_data(&source_node);
+ if (result != NULL) {
+ *result = target_node;
+ }
+ } else if (opline && opline->opcode == ZEND_FETCH_STATIC_PROP_W) {
+ opline->opcode = ZEND_ASSIGN_STATIC_PROP_REF;
+ opline->extended_value &= ~ZEND_FETCH_REF;
+ zend_emit_op_data(&source_node);
+ if (result != NULL) {
+ *result = target_node;
+ }
+ } else {
+ opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node);
+ opline->extended_value = 0;
+ }
if (zend_is_call(source_ast)) {
- opline->extended_value = ZEND_RETURNS_FUNCTION;
+ opline->extended_value |= ZEND_RETURNS_FUNCTION;
}
}
/* }}} */
@@ -2996,13 +3035,25 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
switch (var_ast->kind) {
case ZEND_AST_VAR:
- case ZEND_AST_STATIC_PROP:
offset = zend_delayed_compile_begin();
- zend_delayed_compile_var(&var_node, var_ast, BP_VAR_RW);
+ zend_delayed_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_compile_expr(&expr_node, expr_ast);
zend_delayed_compile_end(offset);
zend_emit_op(result, opcode, &var_node, &expr_node);
return;
+ case ZEND_AST_STATIC_PROP:
+ offset = zend_delayed_compile_begin();
+ zend_delayed_compile_var(result, var_ast, BP_VAR_RW, 0);
+ 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_STATIC_PROP;
+
+ opline = zend_emit_op_data(&expr_node);
+ opline->extended_value = cache_slot;
+ return;
case ZEND_AST_DIM:
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_RW);
@@ -3012,7 +3063,7 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
opline->opcode = opcode;
opline->extended_value = ZEND_ASSIGN_DIM;
- opline = zend_emit_op_data(&expr_node);
+ zend_emit_op_data(&expr_node);
return;
case ZEND_AST_PROP:
offset = zend_delayed_compile_begin();
@@ -3066,7 +3117,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
arg_count++;
if (zend_is_variable(arg)) {
if (zend_is_call(arg)) {
- zend_compile_var(&arg_node, arg, BP_VAR_R);
+ zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
/* Function call was converted into builtin instruction */
opcode = ZEND_SEND_VAL;
@@ -3085,10 +3136,10 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
}
} else if (fbc) {
if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
- zend_compile_var(&arg_node, arg, BP_VAR_W);
+ zend_compile_var(&arg_node, arg, BP_VAR_W, 1);
opcode = ZEND_SEND_REF;
} else {
- zend_compile_var(&arg_node, arg, BP_VAR_R);
+ zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
opcode = (arg_node.op_type == IS_TMP_VAR) ? ZEND_SEND_VAL : ZEND_SEND_VAR;
}
} else {
@@ -3106,7 +3157,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
}
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);
+ zend_compile_var(&arg_node, arg, BP_VAR_FUNC_ARG, 1);
opcode = ZEND_SEND_FUNC_ARG;
} while (0);
}
@@ -3250,7 +3301,7 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(method);
/* 2 slots, for class and method */
- opline->result.num = zend_alloc_polymorphic_cache_slot();
+ opline->result.num = zend_alloc_cache_slots(2);
zval_ptr_dtor(&name_node->u.constant);
} else {
zend_op *opline = get_next_op();
@@ -3980,7 +4031,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(
Z_STR(method_node.u.constant));
- opline->result.num = zend_alloc_polymorphic_cache_slot();
+ opline->result.num = zend_alloc_cache_slots(2);
} else {
SET_NODE(opline->op2, &method_node);
}
@@ -4041,7 +4092,7 @@ 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(
Z_STR(method_node.u.constant));
- opline->result.num = zend_alloc_polymorphic_cache_slot();
+ opline->result.num = zend_alloc_cache_slots(2);
} else {
if (opline->op1_type == IS_CONST) {
opline->result.num = zend_alloc_cache_slot();
@@ -4239,11 +4290,11 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
opline->opcode = ZEND_UNSET_DIM;
return;
case ZEND_AST_PROP:
- opline = zend_compile_prop(NULL, var_ast, BP_VAR_UNSET);
+ opline = zend_compile_prop(NULL, var_ast, BP_VAR_UNSET, 0);
opline->opcode = ZEND_UNSET_OBJ;
return;
case ZEND_AST_STATIC_PROP:
- opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_UNSET, 0);
+ opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_UNSET, 0, 0);
opline->opcode = ZEND_UNSET_STATIC_PROP;
return;
EMPTY_SWITCH_DEFAULT_CASE()
@@ -4356,7 +4407,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
expr_node.op_type = IS_CONST;
ZVAL_NULL(&expr_node.u.constant);
} else if (by_ref && zend_is_variable(expr_ast) && !zend_is_call(expr_ast)) {
- zend_compile_var(&expr_node, expr_ast, BP_VAR_W);
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
} else {
zend_compile_expr(&expr_node, expr_ast);
}
@@ -4714,7 +4765,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
}
if (by_ref && is_variable) {
- zend_compile_var(&expr_node, expr_ast, BP_VAR_W);
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
} else {
zend_compile_expr(&expr_node, expr_ast);
}
@@ -5979,10 +6030,9 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
}
/* }}} */
-void zend_compile_prop_decl(zend_ast *ast) /* {{{ */
+void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags) /* {{{ */
{
zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t flags = list->attr;
zend_class_entry *ce = CG(active_class_entry);
uint32_t i, children = list->children;
@@ -6002,6 +6052,19 @@ void zend_compile_prop_decl(zend_ast *ast) /* {{{ */
zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
zend_string *doc_comment = NULL;
zval value_zv;
+ zend_type type = 0;
+
+ if (type_ast) {
+ type = zend_compile_typename(type_ast, 0);
+
+ if (ZEND_TYPE_CODE(type) == IS_VOID || ZEND_TYPE_CODE(type) == IS_CALLABLE) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Property %s::$%s cannot have type %s",
+ ZSTR_VAL(ce->name),
+ ZSTR_VAL(name),
+ zend_get_type_by_const(ZEND_TYPE_CODE(type)));
+ }
+ }
/* Doc comment has been appended as last element in ZEND_AST_PROP_ELEM ast */
if (doc_comment_ast) {
@@ -6021,15 +6084,58 @@ void zend_compile_prop_decl(zend_ast *ast) /* {{{ */
if (value_ast) {
zend_const_expr_to_zval(&value_zv, value_ast);
- } else {
+
+ if (ZEND_TYPE_IS_SET(type) && !Z_CONSTANT(value_zv)) {
+ if (Z_TYPE(value_zv) == IS_NULL) {
+ if (!ZEND_TYPE_ALLOW_NULL(type)) {
+ const char *name = ZEND_TYPE_IS_CLASS(type)
+ ? ZSTR_VAL(ZEND_TYPE_NAME(type)) : zend_get_type_by_const(ZEND_TYPE_CODE(type));
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Default value for property of type %s may not be null. "
+ "Use the nullable type ?%s to allow null default value",
+ name, name);
+ }
+ } else if (ZEND_TYPE_IS_CLASS(type)) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Property of type %s may not have default value", ZSTR_VAL(ZEND_TYPE_NAME(type)));
+ } else if (ZEND_TYPE_CODE(type) == IS_ARRAY || ZEND_TYPE_CODE(type) == IS_ITERABLE) {
+ if (Z_TYPE(value_zv) != IS_ARRAY) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Default value for property of type %s can only be an array",
+ zend_get_type_by_const(ZEND_TYPE_CODE(type)));
+ }
+ } else if (ZEND_TYPE_CODE(type) == IS_DOUBLE) {
+ if (Z_TYPE(value_zv) != IS_DOUBLE && Z_TYPE(value_zv) != IS_LONG) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Default value for property of type float can only be float or int");
+ }
+ } else if (!ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(type), Z_TYPE(value_zv))) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Default value for property of type %s can only be %s",
+ zend_get_type_by_const(ZEND_TYPE_CODE(type)),
+ zend_get_type_by_const(ZEND_TYPE_CODE(type)));
+ }
+ }
+ } else if (!ZEND_TYPE_IS_SET(type)) {
ZVAL_NULL(&value_zv);
+ } else {
+ ZVAL_UNDEF(&value_zv);
}
- zend_declare_property_ex(ce, name, &value_zv, flags, doc_comment);
+ zend_declare_typed_property(ce, name, &value_zv, flags, doc_comment, type);
}
}
/* }}} */
+void zend_compile_prop_group(zend_ast *list) /* {{{ */
+{
+ zend_ast *type_ast = list->child[0];
+ zend_ast *prop_ast = list->child[1];
+
+ zend_compile_prop_decl(prop_ast, type_ast, list->attr);
+}
+/* }}} */
+
void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */
{
zend_ast_list *list = zend_ast_get_list(ast);
@@ -6378,6 +6484,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
CG(zend_lineno) = decl->end_lineno;
ce->ce_flags |= ZEND_ACC_LINKED;
zend_do_inheritance(ce, parent_ce);
+ zend_build_properties_info_table(ce);
if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
zend_verify_abstract_class(ce);
}
@@ -6389,6 +6496,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
} else {
if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
zend_string_release(lcname);
+ zend_build_properties_info_table(ce);
ce->ce_flags |= ZEND_ACC_LINKED;
return;
}
@@ -7192,12 +7300,16 @@ 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(NULL, var_ast, BP_VAR_RW);
+ zend_op *opline = zend_compile_prop(NULL, var_ast, BP_VAR_RW, 0);
opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ;
zend_make_tmp_result(result, opline);
+ } else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
+ zend_op *opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_RW, 0, 0);
+ opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_STATIC_PROP : ZEND_POST_DEC_STATIC_PROP;
+ zend_make_tmp_result(result, opline);
} else {
znode var_node;
- zend_compile_var(&var_node, var_ast, BP_VAR_RW);
+ zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC,
&var_node, NULL);
}
@@ -7212,11 +7324,14 @@ 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(result, var_ast, BP_VAR_RW);
+ zend_op *opline = zend_compile_prop(result, var_ast, BP_VAR_RW, 0);
opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ;
+ } else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
+ zend_op *opline = zend_compile_static_prop(result, var_ast, BP_VAR_RW, 0, 0);
+ opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_STATIC_PROP : ZEND_PRE_DEC_STATIC_PROP;
} else {
znode var_node;
- zend_compile_var(&var_node, var_ast, BP_VAR_RW);
+ zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_emit_op(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC,
&var_node, NULL);
}
@@ -7310,7 +7425,7 @@ void zend_compile_coalesce(znode *result, zend_ast *ast) /* {{{ */
zend_op *opline;
uint32_t opnum;
- zend_compile_var(&expr_node, expr_ast, BP_VAR_IS);
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_IS, 0);
opnum = get_next_op_number();
zend_emit_op_tmp(result, ZEND_COALESCE, &expr_node, NULL);
@@ -7377,7 +7492,7 @@ void zend_compile_yield(znode *result, zend_ast *ast) /* {{{ */
if (value_ast) {
if (returns_by_ref && zend_is_variable(value_ast) && !zend_is_call(value_ast)) {
- zend_compile_var(&value_node, value_ast, BP_VAR_W);
+ zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
} else {
zend_compile_expr(&value_node, value_ast);
}
@@ -7495,11 +7610,11 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
break;
case ZEND_AST_PROP:
- opline = zend_compile_prop(result, var_ast, BP_VAR_IS);
+ opline = zend_compile_prop(result, var_ast, BP_VAR_IS, 0);
opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
break;
case ZEND_AST_STATIC_PROP:
- opline = zend_compile_static_prop(result, var_ast, BP_VAR_IS, 0);
+ opline = zend_compile_static_prop(result, var_ast, BP_VAR_IS, 0, 0);
opline->opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP;
break;
EMPTY_SWITCH_DEFAULT_CASE()
@@ -7593,7 +7708,7 @@ void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */
if (by_ref) {
zend_ensure_writable_variable(value_ast);
- zend_compile_var(&value_node, value_ast, BP_VAR_W);
+ zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
} else {
zend_compile_expr(&value_node, value_ast);
}
@@ -7709,7 +7824,7 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
zend_set_class_name_op1(opline, &class_node);
- opline->extended_value = zend_alloc_polymorphic_cache_slot();
+ opline->extended_value = zend_alloc_cache_slots(2);
}
/* }}} */
@@ -8146,8 +8261,8 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
case ZEND_AST_METHOD:
zend_compile_func_decl(NULL, ast, 0);
break;
- case ZEND_AST_PROP_DECL:
- zend_compile_prop_decl(ast);
+ case ZEND_AST_PROP_GROUP:
+ zend_compile_prop_group(ast);
break;
case ZEND_AST_CLASS_CONST_DECL:
zend_compile_class_const_decl(ast);
@@ -8207,7 +8322,7 @@ void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */
case ZEND_AST_CALL:
case ZEND_AST_METHOD_CALL:
case ZEND_AST_STATIC_CALL:
- zend_compile_var(result, ast, BP_VAR_R);
+ zend_compile_var(result, ast, BP_VAR_R, 0);
return;
case ZEND_AST_ASSIGN:
zend_compile_assign(result, ast);
@@ -8314,35 +8429,31 @@ void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */
}
/* }}} */
-void zend_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
+zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, int by_ref) /* {{{ */
{
CG(zend_lineno) = zend_ast_get_lineno(ast);
switch (ast->kind) {
case ZEND_AST_VAR:
- zend_compile_simple_var(result, ast, type, 0);
- return;
+ return zend_compile_simple_var(result, ast, type, 0);
case ZEND_AST_DIM:
- zend_compile_dim(result, ast, type);
- return;
+ return zend_compile_dim(result, ast, type);
case ZEND_AST_PROP:
- zend_compile_prop(result, ast, type);
- return;
+ return zend_compile_prop(result, ast, type, by_ref);
case ZEND_AST_STATIC_PROP:
- zend_compile_static_prop(result, ast, type, 0);
- return;
+ return zend_compile_static_prop(result, ast, type, by_ref, 0);
case ZEND_AST_CALL:
zend_compile_call(result, ast, type);
- return;
+ return NULL;
case ZEND_AST_METHOD_CALL:
zend_compile_method_call(result, ast, type);
- return;
+ return NULL;
case ZEND_AST_STATIC_CALL:
zend_compile_static_call(result, ast, type);
- return;
+ return NULL;
case ZEND_AST_ZNODE:
*result = *zend_ast_get_znode(ast);
- return;
+ return NULL;
default:
if (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) {
zend_error_noreturn(E_COMPILE_ERROR,
@@ -8350,29 +8461,30 @@ void zend_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
}
zend_compile_expr(result, ast);
- return;
+ return NULL;
}
}
/* }}} */
-void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
+zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, zend_bool by_ref) /* {{{ */
{
switch (ast->kind) {
case ZEND_AST_VAR:
- zend_compile_simple_var(result, ast, type, 1);
- return;
+ return zend_compile_simple_var(result, ast, type, 1);
case ZEND_AST_DIM:
- zend_delayed_compile_dim(result, ast, type);
- return;
+ return zend_delayed_compile_dim(result, ast, type);
case ZEND_AST_PROP:
- zend_delayed_compile_prop(result, ast, type);
- return;
+ {
+ zend_op *opline = zend_delayed_compile_prop(result, ast, type);
+ if (by_ref) {
+ opline->extended_value |= ZEND_FETCH_REF;
+ }
+ return opline;
+ }
case ZEND_AST_STATIC_PROP:
- zend_compile_static_prop(result, ast, type, 1);
- return;
+ return zend_compile_static_prop(result, ast, type, by_ref, 1);
default:
- zend_compile_var(result, ast, type);
- return;
+ return zend_compile_var(result, ast, type, 0);
}
}
/* }}} */