summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c1457
1 files changed, 996 insertions, 461 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index ad438f6dea..0a505f55e8 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -12,14 +12,12 @@
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Authors: Andi Gutmans <andi@zend.com> |
- | Zeev Suraski <zeev@zend.com> |
- | Dmitry Stogov <dmitry@zend.com> |
+ | Authors: Andi Gutmans <andi@php.net> |
+ | Zeev Suraski <zeev@php.net> |
+ | Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
-/* $Id$ */
-
#define ZEND_INTENSIVE_DEBUGGING 0
#include <stdio.h>
@@ -70,12 +68,20 @@
# define EXECUTE_DATA_DC
# define EXECUTE_DATA_CC
# define NO_EXECUTE_DATA_CC
+# define OPLINE_D void
+# define OPLINE_C
+# define OPLINE_DC
+# define OPLINE_CC
#else
# define EXECUTE_DATA_D zend_execute_data* execute_data
# define EXECUTE_DATA_C execute_data
# define EXECUTE_DATA_DC , EXECUTE_DATA_D
# define EXECUTE_DATA_CC , EXECUTE_DATA_C
# define NO_EXECUTE_DATA_CC , NULL
+# define OPLINE_D const zend_op* opline
+# define OPLINE_C opline
+# define OPLINE_DC , OPLINE_D
+# define OPLINE_CC , OPLINE_C
#endif
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
@@ -93,15 +99,15 @@
typedef int (ZEND_FASTCALL *incdec_t)(zval *);
-#define get_zval_ptr(op_type, node, should_free, type) _get_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
-#define get_zval_ptr_deref(op_type, node, should_free, type) _get_zval_ptr_deref(op_type, node, should_free, type EXECUTE_DATA_CC)
-#define get_zval_ptr_r(op_type, node, should_free) _get_zval_ptr_r(op_type, node, should_free EXECUTE_DATA_CC)
-#define get_zval_ptr_r_deref(op_type, node, should_free) _get_zval_ptr_r_deref(op_type, node, should_free EXECUTE_DATA_CC)
-#define get_zval_ptr_undef(op_type, node, should_free, type) _get_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC)
+#define get_zval_ptr(op_type, node, should_free, type) _get_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
+#define get_zval_ptr_deref(op_type, node, should_free, type) _get_zval_ptr_deref(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
+#define get_zval_ptr_undef(op_type, node, should_free, type) _get_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
+#define get_op_data_zval_ptr_r(op_type, node, should_free) _get_op_data_zval_ptr_r(op_type, node, should_free EXECUTE_DATA_CC OPLINE_CC)
+#define get_op_data_zval_ptr_deref_r(op_type, node, should_free) _get_op_data_zval_ptr_deref_r(op_type, node, should_free EXECUTE_DATA_CC OPLINE_CC)
#define get_zval_ptr_ptr(op_type, node, should_free, type) _get_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
#define get_zval_ptr_ptr_undef(op_type, node, should_free, type) _get_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
-#define get_obj_zval_ptr(op_type, node, should_free, type) _get_obj_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
-#define get_obj_zval_ptr_undef(op_type, node, should_free, type) _get_obj_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC)
+#define get_obj_zval_ptr(op_type, node, should_free, type) _get_obj_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
+#define get_obj_zval_ptr_undef(op_type, node, should_free, type) _get_obj_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
#define get_obj_zval_ptr_ptr(op_type, node, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
#define RETURN_VALUE_USED(opline) ((opline)->result_type != IS_UNUSED)
@@ -128,14 +134,19 @@ ZEND_API const zend_internal_function zend_pass_function = {
#undef zval_ptr_dtor
#define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC)
-#define READY_TO_DESTROY(zv) \
- (UNEXPECTED(zv) && Z_REFCOUNTED_P(zv) && Z_REFCOUNT_P(zv) == 1)
-
-#define EXTRACT_ZVAL_PTR(zv) do { \
- zval *__zv = (zv); \
- if (EXPECTED(Z_TYPE_P(__zv) == IS_INDIRECT)) { \
- ZVAL_COPY(__zv, Z_INDIRECT_P(__zv)); \
- } \
+#define FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op, result) do { \
+ zval *__container_to_free = (free_op); \
+ if (UNEXPECTED(__container_to_free) \
+ && EXPECTED(Z_REFCOUNTED_P(__container_to_free))) { \
+ zend_refcounted *__ref = Z_COUNTED_P(__container_to_free); \
+ if (UNEXPECTED(!GC_DELREF(__ref))) { \
+ zval *__zv = (result); \
+ if (EXPECTED(Z_TYPE_P(__zv) == IS_INDIRECT)) { \
+ ZVAL_COPY(__zv, Z_INDIRECT_P(__zv)); \
+ } \
+ rc_dtor_func(__ref); \
+ } \
+ } \
} while (0)
#define FREE_OP(should_free) \
@@ -159,12 +170,9 @@ ZEND_API const zend_internal_function zend_pass_function = {
#define ZEND_VM_STACK_PAGE_SIZE (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval))
-#define ZEND_VM_STACK_FREE_PAGE_SIZE \
- ((ZEND_VM_STACK_PAGE_SLOTS - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval))
-
-#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size) \
+#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size, page_size) \
(((size) + ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval) \
- + (ZEND_VM_STACK_PAGE_SIZE - 1)) & ~(ZEND_VM_STACK_PAGE_SIZE - 1))
+ + ((page_size) - 1)) & ~((page_size) - 1))
static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
zend_vm_stack page = (zend_vm_stack)emalloc(size);
@@ -177,12 +185,23 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend
ZEND_API void zend_vm_stack_init(void)
{
+ EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE;
EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL);
EG(vm_stack)->top++;
EG(vm_stack_top) = EG(vm_stack)->top;
EG(vm_stack_end) = EG(vm_stack)->end;
}
+ZEND_API void zend_vm_stack_init_ex(size_t page_size)
+{
+ /* page_size must be a power of 2 */
+ ZEND_ASSERT(page_size > 0 && (page_size & (page_size - 1)) == 0);
+ EG(vm_stack_page_size) = page_size;
+ EG(vm_stack) = zend_vm_stack_new_page(page_size, NULL);
+ EG(vm_stack_top) = EG(vm_stack)->top;
+ EG(vm_stack_end) = EG(vm_stack)->end;
+}
+
ZEND_API void zend_vm_stack_destroy(void)
{
zend_vm_stack stack = EG(vm_stack);
@@ -202,8 +221,8 @@ ZEND_API void* zend_vm_stack_extend(size_t size)
stack = EG(vm_stack);
stack->top = EG(vm_stack_top);
EG(vm_stack) = stack = zend_vm_stack_new_page(
- EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE) ?
- ZEND_VM_STACK_PAGE_SIZE : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size),
+ EXPECTED(size < EG(vm_stack_page_size) - (ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval))) ?
+ EG(vm_stack_page_size) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size, EG(vm_stack_page_size)),
stack);
ptr = stack->top;
EG(vm_stack_top) = (void*)(((char*)ptr) + size);
@@ -251,7 +270,7 @@ static zend_never_inline ZEND_COLD void zval_undefined_cv(uint32_t var EXECUTE_D
}
}
-static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type EXECUTE_DATA_DC)
+static zend_never_inline ZEND_COLD zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type EXECUTE_DATA_DC)
{
switch (type) {
case BP_VAR_R:
@@ -271,52 +290,50 @@ static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int
return ptr;
}
-static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, uint32_t var EXECUTE_DATA_DC)
+static zend_never_inline ZEND_COLD zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, uint32_t var EXECUTE_DATA_DC)
{
zval_undefined_cv(var EXECUTE_DATA_CC);
return &EG(uninitialized_zval);
}
-static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, uint32_t var EXECUTE_DATA_DC)
+static zend_never_inline ZEND_COLD zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, uint32_t var EXECUTE_DATA_DC)
{
zval_undefined_cv(var EXECUTE_DATA_CC);
return &EG(uninitialized_zval);
}
-static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, uint32_t var EXECUTE_DATA_DC)
+static zend_never_inline ZEND_COLD zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, uint32_t var EXECUTE_DATA_DC)
{
ZVAL_NULL(ptr);
zval_undefined_cv(var EXECUTE_DATA_CC);
return ptr;
}
-static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, uint32_t var EXECUTE_DATA_DC)
-{
- ZVAL_NULL(ptr);
- return ptr;
-}
-
static zend_always_inline zval *_get_zval_ptr_cv(uint32_t var, int type EXECUTE_DATA_DC)
{
zval *ret = EX_VAR(var);
if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
- return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
+ if (type == BP_VAR_W) {
+ ZVAL_NULL(ret);
+ } else {
+ return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
+ }
}
return ret;
}
-static zend_always_inline zval *_get_zval_ptr_cv_undef(uint32_t var EXECUTE_DATA_DC)
-{
- return EX_VAR(var);
-}
-
static zend_always_inline zval *_get_zval_ptr_cv_deref(uint32_t var, int type EXECUTE_DATA_DC)
{
zval *ret = EX_VAR(var);
if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
- return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
+ if (type == BP_VAR_W) {
+ ZVAL_NULL(ret);
+ return ret;
+ } else {
+ return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
+ }
}
ZVAL_DEREF(ret);
return ret;
@@ -405,38 +422,24 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(uint32_t var EXECUTE_D
zval *ret = EX_VAR(var);
if (Z_TYPE_P(ret) == IS_UNDEF) {
- return _get_zval_cv_lookup_BP_VAR_W(ret, var EXECUTE_DATA_CC);
+ ZVAL_NULL(ret);
}
return ret;
}
-static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(uint32_t var EXECUTE_DATA_DC)
-{
- return EX_VAR(var);
-}
-
-static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_RW(uint32_t var EXECUTE_DATA_DC)
-{
- return EX_VAR(var);
-}
-
-static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_UNSET(uint32_t var EXECUTE_DATA_DC)
-{
- return EX_VAR(var);
-}
-
static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(uint32_t var EXECUTE_DATA_DC)
{
zval *ret = EX_VAR(var);
if (Z_TYPE_P(ret) == IS_UNDEF) {
- return _get_zval_cv_lookup_BP_VAR_W(ret, var EXECUTE_DATA_CC);
+ ZVAL_NULL(ret);
+ return ret;
}
ZVAL_DEREF(ret);
return ret;
}
-static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC)
+static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type & (IS_TMP_VAR|IS_VAR)) {
if (op_type == IS_TMP_VAR) {
@@ -448,7 +451,7 @@ static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, zend_f
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
- return EX_CONSTANT(node);
+ return RT_CONSTANT(opline, node);
} else if (op_type == IS_CV) {
return _get_zval_ptr_cv(node.var, type EXECUTE_DATA_CC);
} else {
@@ -457,7 +460,7 @@ static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, zend_f
}
}
-static zend_always_inline zval *_get_zval_ptr_r(int op_type, znode_op node, zend_free_op *should_free EXECUTE_DATA_DC)
+static zend_always_inline zval *_get_op_data_zval_ptr_r(int op_type, znode_op node, zend_free_op *should_free EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type & (IS_TMP_VAR|IS_VAR)) {
if (op_type == IS_TMP_VAR) {
@@ -469,7 +472,7 @@ static zend_always_inline zval *_get_zval_ptr_r(int op_type, znode_op node, zend
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
- return EX_CONSTANT(node);
+ return RT_CONSTANT(opline + 1, node);
} else if (op_type == IS_CV) {
return _get_zval_ptr_cv_BP_VAR_R(node.var EXECUTE_DATA_CC);
} else {
@@ -478,7 +481,7 @@ static zend_always_inline zval *_get_zval_ptr_r(int op_type, znode_op node, zend
}
}
-static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC)
+static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type & (IS_TMP_VAR|IS_VAR)) {
if (op_type == IS_TMP_VAR) {
@@ -490,7 +493,7 @@ static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node,
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
- return EX_CONSTANT(node);
+ return RT_CONSTANT(opline, node);
} else if (op_type == IS_CV) {
return _get_zval_ptr_cv_deref(node.var, type EXECUTE_DATA_CC);
} else {
@@ -499,7 +502,7 @@ static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node,
}
}
-static zend_always_inline zval *_get_zval_ptr_r_deref(int op_type, znode_op node, zend_free_op *should_free EXECUTE_DATA_DC)
+static zend_always_inline zval *_get_op_data_zval_ptr_deref_r(int op_type, znode_op node, zend_free_op *should_free EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type & (IS_TMP_VAR|IS_VAR)) {
if (op_type == IS_TMP_VAR) {
@@ -511,7 +514,7 @@ static zend_always_inline zval *_get_zval_ptr_r_deref(int op_type, znode_op node
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
- return EX_CONSTANT(node);
+ return RT_CONSTANT(opline + 1, node);
} else if (op_type == IS_CV) {
return _get_zval_ptr_cv_deref_BP_VAR_R(node.var EXECUTE_DATA_CC);
} else {
@@ -520,7 +523,7 @@ static zend_always_inline zval *_get_zval_ptr_r_deref(int op_type, znode_op node
}
}
-static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC)
+static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, zend_free_op *should_free, int type EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type & (IS_TMP_VAR|IS_VAR)) {
if (op_type == IS_TMP_VAR) {
@@ -532,9 +535,9 @@ static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node,
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
- return EX_CONSTANT(node);
+ return RT_CONSTANT(opline, node);
} else if (op_type == IS_CV) {
- return _get_zval_ptr_cv_undef(node.var EXECUTE_DATA_CC);
+ return EX_VAR(node.var);
} else {
return NULL;
}
@@ -565,12 +568,7 @@ static inline zval *_get_zval_ptr_ptr(int op_type, znode_op node, zend_free_op *
}
}
-static zend_always_inline zval *_get_obj_zval_ptr_unused(EXECUTE_DATA_D)
-{
- return &EX(This);
-}
-
-static inline zval *_get_obj_zval_ptr(int op_type, znode_op op, zend_free_op *should_free, int type EXECUTE_DATA_DC)
+static inline zval *_get_obj_zval_ptr(int op_type, znode_op op, zend_free_op *should_free, int type EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type == IS_UNUSED) {
*should_free = NULL;
@@ -579,7 +577,7 @@ static inline zval *_get_obj_zval_ptr(int op_type, znode_op op, zend_free_op *sh
return get_zval_ptr(op_type, op, should_free, type);
}
-static inline zval *_get_obj_zval_ptr_undef(int op_type, znode_op op, zend_free_op *should_free, int type EXECUTE_DATA_DC)
+static inline zval *_get_obj_zval_ptr_undef(int op_type, znode_op op, zend_free_op *should_free, int type EXECUTE_DATA_DC OPLINE_DC)
{
if (op_type == IS_UNUSED) {
*should_free = NULL;
@@ -608,13 +606,13 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v
}
ref = Z_REF_P(value_ptr);
- GC_REFCOUNT(ref)++;
+ GC_ADDREF(ref);
if (Z_REFCOUNTED_P(variable_ptr)) {
zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
- if (--GC_REFCOUNT(garbage) == 0) {
+ if (GC_DELREF(garbage) == 0) {
ZVAL_REF(variable_ptr, ref);
- zval_dtor_func(garbage);
+ rc_dtor_func(garbage);
return;
} else {
gc_check_possible_root(garbage);
@@ -623,20 +621,93 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v
ZVAL_REF(variable_ptr, ref);
}
+static zend_never_inline ZEND_COLD int zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr, zend_uchar value_type OPLINE_DC EXECUTE_DATA_DC)
+{
+ zend_error(E_NOTICE, "Only variables should be assigned by reference");
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ return 0;
+ }
+
+ value_ptr = zend_assign_to_variable(variable_ptr, value_ptr, value_type);
+
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), value_ptr);
+ }
+ return 1;
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_assignment(zval *property OPLINE_DC EXECUTE_DATA_DC)
+{
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+ zend_error(E_WARNING, "Attempt to assign property '%s' of non-object", ZSTR_VAL(property_name));
+ zend_tmp_string_release(tmp_property_name);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
+ }
+}
+
/* this should modify object only if it's empty */
-static inline int make_real_object(zval *object)
+static zend_never_inline ZEND_COLD int ZEND_FASTCALL make_real_object(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC)
{
- if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
- if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
- /* nothing to destroy */
- } else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
- zval_ptr_dtor_nogc(object);
- } else {
- return 0;
+ zend_object *obj;
+
+ if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
+ /* nothing to destroy */
+ } else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
+ zval_ptr_dtor_nogc(object);
+ } else {
+ if (opline->op1_type != IS_VAR || EXPECTED(!Z_ISERROR_P(object))) {
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+
+ if (opline->opcode == ZEND_PRE_INC_OBJ
+ || opline->opcode == ZEND_PRE_DEC_OBJ
+ || opline->opcode == ZEND_POST_INC_OBJ
+ || opline->opcode == ZEND_POST_DEC_OBJ) {
+ zend_error(E_WARNING, "Attempt to increment/decrement property '%s' of non-object", ZSTR_VAL(property_name));
+ } else {
+ zend_error(E_WARNING, "Attempt to assign property '%s' of non-object", ZSTR_VAL(property_name));
+ }
+ zend_tmp_string_release(tmp_property_name);
+ }
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
- object_init(object);
- zend_error(E_WARNING, "Creating default object from empty value");
+ return 0;
}
+ object_init(object);
+ Z_ADDREF_P(object);
+ obj = Z_OBJ_P(object);
+ zend_error(E_WARNING, "Creating default object from empty value");
+ if (GC_REFCOUNT(obj) == 1) {
+ /* the enclosing container was deleted, obj is unreferenced */
+ OBJ_RELEASE(obj);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
+ }
+ return 0;
+ }
+ Z_DELREF_P(object);
+ return 1;
+}
+
+static zend_never_inline ZEND_COLD int ZEND_FASTCALL make_real_object_rw(zval *object, zval *property OPLINE_DC)
+{
+ if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
+ /* nothing to destroy */
+ } else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
+ zval_ptr_dtor_nogc(object);
+ } else {
+ if (opline->op1_type != IS_VAR || EXPECTED(!Z_ISERROR_P(object))) {
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+ zend_error(E_WARNING, "Attempt to modify property '%s' of non-object", ZSTR_VAL(property_name));
+ zend_tmp_string_release(tmp_property_name);
+ }
+ return 0;
+ }
+ object_init(object);
return 1;
}
@@ -744,7 +815,7 @@ static ZEND_COLD void zend_verify_arg_error(
static int is_null_constant(zend_class_entry *scope, zval *default_value)
{
- if (Z_CONSTANT_P(default_value)) {
+ if (Z_TYPE_P(default_value) == IS_CONSTANT_AST) {
zval constant;
ZVAL_COPY(&constant, default_value);
@@ -754,7 +825,7 @@ static int is_null_constant(zend_class_entry *scope, zval *default_value)
if (Z_TYPE(constant) == IS_NULL) {
return 1;
}
- zval_ptr_dtor(&constant);
+ zval_ptr_dtor_nogc(&constant);
}
return 0;
}
@@ -883,6 +954,7 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
return 1;
}
+ ce = NULL;
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0))) {
zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg);
return 0;
@@ -1017,7 +1089,7 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval *
}
}
-static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **cache_slot)
+static ZEND_COLD int zend_verify_missing_return_type(const zend_function *zf, void **cache_slot)
{
zend_arg_info *ret_info = zf->common.arg_info - 1;
@@ -1039,14 +1111,31 @@ static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **c
return 1;
}
-static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value)
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array(void)
+{
+ zend_throw_error(NULL, "Cannot use object as array");
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset(void)
+{
+ zend_error(E_WARNING, "Illegal offset type");
+}
+
+static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
{
if (UNEXPECTED(!Z_OBJ_HT_P(object)->write_dimension)) {
- zend_throw_error(NULL, "Cannot use object as array");
+ zend_use_object_as_array();
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ }
return;
}
Z_OBJ_HT_P(object)->write_dimension(object, dim, value);
+
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ }
}
static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, binary_op_type binary_op EXECUTE_DATA_DC)
@@ -1076,7 +1165,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *
}
zval_ptr_dtor(&res);
} else {
- zend_error(E_WARNING, "Attempt to assign property of non-object");
+ zend_use_object_as_array();
if (retval) {
ZVAL_NULL(retval);
}
@@ -1110,11 +1199,11 @@ try_again:
dim = Z_REFVAL_P(dim);
goto try_again;
default:
- zend_error(E_WARNING, "Illegal offset type");
+ zend_illegal_offset();
break;
}
- offset = _zval_get_long_func(dim);
+ offset = zval_get_long_func(dim);
} else {
offset = Z_LVAL_P(dim);
}
@@ -1129,6 +1218,10 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
const zend_op *end;
uint32_t var;
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ return;
+ }
+
switch (opline->opcode) {
case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB:
@@ -1148,6 +1241,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
+ case ZEND_FETCH_LIST_W:
/* TODO: Encode the "reason" into opline->extended_value??? */
var = opline->result.var;
opline++;
@@ -1190,6 +1284,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
+ case ZEND_FETCH_LIST_W:
case ZEND_ASSIGN_DIM:
msg = "Cannot use string offset as an array";
break;
@@ -1219,6 +1314,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
break;
case ZEND_SEND_REF:
case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
msg = "Only variables can be passed by reference";
break;
case ZEND_FE_RESET_RW:
@@ -1238,12 +1334,43 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
EMPTY_SWITCH_DEFAULT_CASE();
}
ZEND_ASSERT(msg != NULL);
- zend_throw_error(NULL, msg);
+ zend_throw_error(NULL, "%s", msg);
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_read(zval *property)
+{
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+ zend_error(E_NOTICE, "Trying to get property '%s' of non-object", ZSTR_VAL(property_name));
+ zend_tmp_string_release(tmp_property_name);
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_unset(zval *property)
+{
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+ zend_error(E_NOTICE, "Trying to unset property '%s' of non-object", ZSTR_VAL(property_name));
+ zend_tmp_string_release(tmp_property_name);
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_check(zval *property)
+{
+ zend_string *tmp_property_name;
+ zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
+ zend_error(E_NOTICE, "Trying to check property '%s' of non-object", ZSTR_VAL(property_name));
+ zend_tmp_string_release(tmp_property_name);
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
+{
+ zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
+ fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "",
+ fbc->common.scope ? "::" : "",
+ ZSTR_VAL(fbc->common.function_name));
}
-static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result EXECUTE_DATA_DC)
+static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
{
- zend_string *old_str;
zend_uchar c;
size_t string_len;
zend_long offset;
@@ -1252,19 +1379,19 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
if (offset < -(zend_long)Z_STRLEN_P(str)) {
/* Error on negative offset */
zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset);
- if (result) {
- ZVAL_NULL(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
return;
}
if (Z_TYPE_P(value) != IS_STRING) {
/* Convert to string, just the time to pick the 1st byte */
- zend_string *tmp = zval_get_string(value);
+ zend_string *tmp = zval_get_string_func(value);
string_len = ZSTR_LEN(tmp);
c = (zend_uchar)ZSTR_VAL(tmp)[0];
- zend_string_release(tmp);
+ zend_string_release_ex(tmp, 0);
} else {
string_len = Z_STRLEN_P(value);
c = (zend_uchar)Z_STRVAL_P(value)[0];
@@ -1273,8 +1400,8 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
if (string_len == 0) {
/* Error on empty input string */
zend_error(E_WARNING, "Cannot assign an empty string to a string offset");
- if (result) {
- ZVAL_NULL(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
return;
}
@@ -1286,29 +1413,27 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
if ((size_t)offset >= Z_STRLEN_P(str)) {
/* Extend string if needed */
zend_long old_len = Z_STRLEN_P(str);
- Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
- Z_TYPE_INFO_P(str) = IS_STRING_EX;
+ ZVAL_NEW_STR(str, zend_string_extend(Z_STR_P(str), offset + 1, 0));
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
Z_STRVAL_P(str)[offset+1] = 0;
} else if (!Z_REFCOUNTED_P(str)) {
- old_str = Z_STR_P(str);
- Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
- Z_TYPE_INFO_P(str) = IS_STRING_EX;
- zend_string_release(old_str);
+ ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
+ } else if (Z_REFCOUNT_P(str) > 1) {
+ Z_DELREF_P(str);
+ ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
} else {
- SEPARATE_STRING(str);
zend_string_forget_hash_val(Z_STR_P(str));
}
Z_STRVAL_P(str)[offset] = c;
- if (result) {
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
/* Return the new character */
- ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
+ ZVAL_INTERNED_STR(EX_VAR(opline->result.var), ZSTR_CHAR(c));
}
}
-static zend_never_inline void zend_post_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc, zval *result)
+static zend_never_inline void zend_post_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc OPLINE_DC EXECUTE_DATA_DC)
{
if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
zval rv, obj;
@@ -1320,7 +1445,7 @@ static zend_never_inline void zend_post_incdec_overloaded_property(zval *object,
z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
if (UNEXPECTED(EG(exception))) {
OBJ_RELEASE(Z_OBJ(obj));
- ZVAL_UNDEF(result);
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
return;
}
@@ -1333,12 +1458,8 @@ static zend_never_inline void zend_post_incdec_overloaded_property(zval *object,
ZVAL_COPY_VALUE(z, value);
}
- if (UNEXPECTED(Z_TYPE_P(z) == IS_REFERENCE)) {
- ZVAL_COPY(result, Z_REFVAL_P(z));
- } else {
- ZVAL_COPY(result, z);
- }
- ZVAL_DUP(&z_copy, result);
+ ZVAL_COPY_DEREF(&z_copy, z);
+ ZVAL_COPY(EX_VAR(opline->result.var), &z_copy);
if (inc) {
increment_function(&z_copy);
} else {
@@ -1350,24 +1471,25 @@ static zend_never_inline void zend_post_incdec_overloaded_property(zval *object,
zval_ptr_dtor(z);
} else {
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
- ZVAL_NULL(result);
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
}
-static zend_never_inline void zend_pre_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc, zval *result)
+static zend_never_inline void zend_pre_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc OPLINE_DC EXECUTE_DATA_DC)
{
zval rv;
if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
- zval *z, *zptr, obj;
+ zval *z, obj;
+ zval z_copy;
ZVAL_OBJ(&obj, Z_OBJ_P(object));
Z_ADDREF(obj);
- zptr = z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
+ z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
if (UNEXPECTED(EG(exception))) {
OBJ_RELEASE(Z_OBJ(obj));
- if (result) {
- ZVAL_UNDEF(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
return;
}
@@ -1381,32 +1503,31 @@ static zend_never_inline void zend_pre_incdec_overloaded_property(zval *object,
}
ZVAL_COPY_VALUE(z, value);
}
- ZVAL_DEREF(z);
- SEPARATE_ZVAL_NOREF(z);
+ ZVAL_COPY_DEREF(&z_copy, z);
if (inc) {
- increment_function(z);
+ increment_function(&z_copy);
} else {
- decrement_function(z);
+ decrement_function(&z_copy);
}
- if (UNEXPECTED(result)) {
- ZVAL_COPY(result, z);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), &z_copy);
}
- Z_OBJ_HT(obj)->write_property(&obj, property, z, cache_slot);
+ Z_OBJ_HT(obj)->write_property(&obj, property, &z_copy, cache_slot);
OBJ_RELEASE(Z_OBJ(obj));
- zval_ptr_dtor(zptr);
+ zval_ptr_dtor(&z_copy);
+ zval_ptr_dtor(z);
} else {
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
- if (UNEXPECTED(result)) {
- ZVAL_NULL(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
}
}
-static zend_never_inline void zend_assign_op_overloaded_property(zval *object, zval *property, void **cache_slot, zval *value, binary_op_type binary_op, zval *result)
+static zend_never_inline void zend_assign_op_overloaded_property(zval *object, zval *property, void **cache_slot, zval *value, binary_op_type binary_op OPLINE_DC EXECUTE_DATA_DC)
{
zval *z;
- zval rv, obj;
- zval *zptr;
+ zval rv, obj, res;
ZVAL_OBJ(&obj, Z_OBJ_P(object));
Z_ADDREF(obj);
@@ -1414,8 +1535,8 @@ static zend_never_inline void zend_assign_op_overloaded_property(zval *object, z
z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
if (UNEXPECTED(EG(exception))) {
OBJ_RELEASE(Z_OBJ(obj));
- if (result) {
- ZVAL_UNDEF(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
}
return;
}
@@ -1428,19 +1549,17 @@ static zend_never_inline void zend_assign_op_overloaded_property(zval *object, z
}
ZVAL_COPY_VALUE(z, value);
}
- zptr = z;
- ZVAL_DEREF(z);
- SEPARATE_ZVAL_NOREF(z);
- binary_op(z, z, value);
- Z_OBJ_HT(obj)->write_property(&obj, property, z, cache_slot);
- if (UNEXPECTED(result)) {
- ZVAL_COPY(result, z);
+ binary_op(&res, z, value);
+ Z_OBJ_HT(obj)->write_property(&obj, property, &res, cache_slot);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), &res);
}
- zval_ptr_dtor(zptr);
+ zval_ptr_dtor(z);
+ zval_ptr_dtor(&res);
} else {
zend_error(E_WARNING, "Attempt to assign property of non-object");
- if (UNEXPECTED(result)) {
- ZVAL_NULL(result);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
}
OBJ_RELEASE(Z_OBJ(obj));
@@ -1475,11 +1594,10 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(int fetch_type
{
HashTable *ht;
- if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) ||
- EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) {
+ if (EXPECTED(fetch_type & (ZEND_FETCH_GLOBAL_LOCK | ZEND_FETCH_GLOBAL))) {
ht = &EG(symbol_table);
} else {
- ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
+ ZEND_ASSERT(fetch_type & ZEND_FETCH_LOCAL);
if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_rebuild_symbol_table();
}
@@ -1488,9 +1606,82 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(int fetch_type
return ht;
}
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_offset(zend_long lval)
+{
+ zend_error(E_NOTICE, "Undefined offset: " ZEND_LONG_FMT, lval);
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_index(const zend_string *offset)
+{
+ zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset));
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(const zend_class_entry *ce, const zend_string *method)
+{
+ zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(method));
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(zval *object, zval *function_name)
+{
+ zend_throw_error(NULL, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object)));
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc)
+{
+ if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+ zend_error(E_DEPRECATED,
+ "Non-static method %s::%s() should not be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ } else {
+ zend_throw_error(
+ zend_ce_error,
+ "Non-static method %s::%s() cannot be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ }
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num)
+{
+ zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
+ arg_num,
+ func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
+ func->common.scope ? "::" : "",
+ ZSTR_VAL(func->common.function_name));
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_scalar_as_array(void)
+{
+ zend_error(E_WARNING, "Cannot use a scalar value as an array");
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void)
+{
+ zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim)
+{
+ zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_string(void)
+{
+ zend_throw_error(NULL, "[] operator not supported for strings");
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_access_undefined_propery_in_overloaded_object(void)
+{
+ zend_throw_error(NULL, "Cannot access undefined property for object with overloaded property access");
+}
+
+static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_unsupported_property_reference(void)
+{
+ zend_error(E_WARNING, "This object doesn't support property references");
+}
+
static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type EXECUTE_DATA_DC)
{
- zval *retval;
+ zval *retval = NULL;
zend_string *offset_key;
zend_ulong hval;
@@ -1503,14 +1694,14 @@ num_index:
num_undef:
switch (type) {
case BP_VAR_R:
- zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ zend_undefined_offset(hval);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
- zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ zend_undefined_offset(hval);
retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
break;
case BP_VAR_W:
@@ -1525,7 +1716,7 @@ num_undef:
}
}
str_index:
- retval = zend_hash_find(ht, offset_key);
+ retval = zend_hash_find_ex(ht, offset_key, dim_type == IS_CONST);
if (retval) {
/* support for $GLOBALS[...] */
if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
@@ -1533,14 +1724,14 @@ str_index:
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
switch (type) {
case BP_VAR_R:
- zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ zend_undefined_index(offset_key);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
- zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
+ zend_undefined_index(offset_key);
/* break missing intentionally */
case BP_VAR_W:
ZVAL_NULL(retval);
@@ -1551,14 +1742,14 @@ str_index:
} else {
switch (type) {
case BP_VAR_R:
- zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ zend_undefined_index(offset_key);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
- zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
+ zend_undefined_index(offset_key);
retval = zend_hash_update(ht, offset_key, &EG(uninitialized_zval));
break;
case BP_VAR_W:
@@ -1578,7 +1769,7 @@ str_index:
hval = zend_dval_to_lval(Z_DVAL_P(dim));
goto num_index;
case IS_RESOURCE:
- zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ zend_use_resource_as_offset(dim);
hval = Z_RES_HANDLE_P(dim);
goto num_index;
case IS_FALSE:
@@ -1591,7 +1782,7 @@ str_index:
dim = Z_REFVAL_P(dim);
goto try_again;
default:
- zend_error(E_WARNING, "Illegal offset type");
+ zend_illegal_offset();
retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
NULL : &EG(uninitialized_zval);
}
@@ -1630,7 +1821,7 @@ fetch_from_array:
if (dim == NULL) {
retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
if (UNEXPECTED(retval == NULL)) {
- zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
+ zend_cannot_add_element();
ZVAL_ERROR(result);
return;
}
@@ -1651,12 +1842,10 @@ fetch_from_array:
}
if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
if (dim == NULL) {
- zend_throw_error(NULL, "[] operator not supported for strings");
+ zend_use_new_element_for_string();
} else {
zend_check_string_offset(dim, type EXECUTE_DATA_CC);
- if (EXPECTED(EG(exception) == NULL)) {
- zend_wrong_string_offset(EXECUTE_DATA_C);
- }
+ zend_wrong_string_offset(EXECUTE_DATA_C);
}
ZVAL_ERROR(result);
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
@@ -1665,9 +1854,12 @@ fetch_from_array:
dim = &EG(uninitialized_zval);
}
if (!Z_OBJ_HT_P(container)->read_dimension) {
- zend_throw_error(NULL, "Cannot use object as array");
+ zend_use_object_as_array();
ZVAL_ERROR(result);
} else {
+ if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
+ dim++;
+ }
retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
@@ -1704,8 +1896,7 @@ fetch_from_array:
}
if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
if (type != BP_VAR_UNSET) {
- ZVAL_NEW_ARR(container);
- zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
+ array_init(container);
goto fetch_from_array;
} else {
/* for read-mode only */
@@ -1718,25 +1909,28 @@ fetch_from_array:
zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
ZVAL_NULL(result);
} else {
- zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ zend_use_scalar_as_array();
ZVAL_ERROR(result);
}
}
}
}
-static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_W(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W EXECUTE_DATA_CC);
}
-static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_RW(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW EXECUTE_DATA_CC);
}
-static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET EXECUTE_DATA_CC);
}
@@ -1748,7 +1942,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
try_array:
retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC);
- ZVAL_COPY(result, retval);
+ ZVAL_COPY_DEREF(result, retval);
return;
} else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
container = Z_REFVAL_P(container);
@@ -1788,11 +1982,11 @@ try_string_offset:
dim = Z_REFVAL_P(dim);
goto try_string_offset;
default:
- zend_error(E_WARNING, "Illegal offset type");
+ zend_illegal_offset();
break;
}
- offset = _zval_get_long_func(dim);
+ offset = zval_get_long_func(dim);
} else {
offset = Z_LVAL_P(dim);
}
@@ -1820,15 +2014,20 @@ try_string_offset:
dim = &EG(uninitialized_zval);
}
if (!Z_OBJ_HT_P(container)->read_dimension) {
- zend_throw_error(NULL, "Cannot use object as array");
+ zend_use_object_as_array();
ZVAL_NULL(result);
} else {
+ if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
+ dim++;
+ }
retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
ZEND_ASSERT(result != NULL);
if (retval) {
if (result != retval) {
- ZVAL_COPY(result, retval);
+ ZVAL_COPY_DEREF(result, retval);
+ } else if (UNEXPECTED(Z_ISREF_P(retval))) {
+ zend_unwrap_reference(result);
}
} else {
ZVAL_NULL(result);
@@ -1845,36 +2044,155 @@ try_string_offset:
}
}
-static zend_never_inline void zend_fetch_dimension_address_read_R(zval *result, zval *container, zval *dim, int dim_type EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0 EXECUTE_DATA_CC);
}
-static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *result, zval *container, zval *dim EXECUTE_DATA_DC)
+static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 1, 1 EXECUTE_DATA_CC);
}
-static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zval *container, zval *dim, int dim_type EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
+ zval *result = EX_VAR(opline->result.var);
zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1, 0 EXECUTE_DATA_CC);
}
-static zend_never_inline void zend_fetch_dimension_address_read_LIST(zval *result, zval *container, zval *dim EXECUTE_DATA_DC)
+static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
{
- zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, BP_VAR_R, 0, 0 EXECUTE_DATA_CC);
+ zval *result = EX_VAR(opline->result.var);
+ zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0 EXECUTE_DATA_CC);
}
ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type)
{
- if (type == BP_VAR_IS) {
- zend_fetch_dimension_address_read_IS(result, container, dim, IS_CONST NO_EXECUTE_DATA_CC);
+ zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 1, 0 NO_EXECUTE_DATA_CC);
+}
+
+static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, zval *offset EXECUTE_DATA_DC)
+{
+ zend_ulong hval;
+
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ hval = zend_dval_to_lval(Z_DVAL_P(offset));
+num_idx:
+ return zend_hash_index_find(ht, hval);
+ } else if (Z_TYPE_P(offset) == IS_NULL) {
+str_idx:
+ return zend_hash_find_ex_ind(ht, ZSTR_EMPTY_ALLOC(), 1);
+ } else if (Z_TYPE_P(offset) == IS_FALSE) {
+ hval = 0;
+ goto num_idx;
+ } else if (Z_TYPE_P(offset) == IS_TRUE) {
+ hval = 1;
+ goto num_idx;
+ } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+ hval = Z_RES_HANDLE_P(offset);
+ goto num_idx;
+ } else if (/*OP2_TYPE == IS_CV &&*/ Z_TYPE_P(offset) == IS_UNDEF) {
+ zval_undefined_cv(EX(opline)->op2.var EXECUTE_DATA_CC);
+ goto str_idx;
} else {
- zend_fetch_dimension_address_read_R(result, container, dim, IS_CONST NO_EXECUTE_DATA_CC);
+ zend_error(E_WARNING, "Illegal offset type in isset or empty");
+ return NULL;
}
}
-static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type)
+static zend_never_inline int ZEND_FASTCALL zend_isset_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC)
+{
+ if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
+ zval_undefined_cv(EX(opline)->op2.var EXECUTE_DATA_CC);
+ offset = &EG(uninitialized_zval);
+ }
+
+ if (/*OP1_TYPE != IS_CONST &&*/ EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ if (EXPECTED(Z_OBJ_HT_P(container)->has_dimension)) {
+ return Z_OBJ_HT_P(container)->has_dimension(container, offset, 0);
+ } else {
+ zend_use_object_as_array();
+ return 0;
+ }
+ } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
+ zend_long lval;
+
+ if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+ lval = Z_LVAL_P(offset);
+str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
+ if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ /*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
+ ZVAL_DEREF(offset);
+ /*}*/
+ if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
+ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
+ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) {
+ lval = zval_get_long(offset);
+ goto str_offset;
+ }
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+}
+
+static zend_never_inline int ZEND_FASTCALL zend_isempty_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC)
+{
+ if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
+ zval_undefined_cv(EX(opline)->op2.var EXECUTE_DATA_CC);
+ offset = &EG(uninitialized_zval);
+ }
+
+ if (/*OP1_TYPE != IS_CONST &&*/ EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ if (EXPECTED(Z_OBJ_HT_P(container)->has_dimension)) {
+ return !Z_OBJ_HT_P(container)->has_dimension(container, offset, 1);
+ } else {
+ zend_use_object_as_array();
+ return 1;
+ }
+ } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
+ zend_long lval;
+
+ if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+ lval = Z_LVAL_P(offset);
+str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
+ if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
+ return (Z_STRVAL_P(container)[lval] == '0');
+ } else {
+ return 1;
+ }
+ } else {
+ /*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
+ ZVAL_DEREF(offset);
+ /*}*/
+ if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
+ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
+ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) {
+ lval = zval_get_long(offset);
+ goto str_offset;
+ }
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+}
+
+static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type OPLINE_DC)
{
if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
do {
@@ -1886,17 +2204,8 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
}
/* this should modify object only if it's empty */
- if (type != BP_VAR_UNSET &&
- EXPECTED(Z_TYPE_P(container) <= IS_FALSE ||
- (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0))) {
- zval_ptr_dtor_nogc(container);
- object_init(container);
- } else {
- if (container_op_type != IS_VAR || EXPECTED(!Z_ISERROR_P(container))) {
- zend_string *property_name = zval_get_string(prop_ptr);
- zend_error(E_WARNING, "Attempt to modify property '%s' of non-object", ZSTR_VAL(property_name));
- zend_string_release(property_name);
- }
+ if (type == BP_VAR_UNSET ||
+ UNEXPECTED(!make_real_object_rw(container, prop_ptr OPLINE_CC))) {
ZVAL_ERROR(result);
return;
}
@@ -1904,11 +2213,11 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
}
if (prop_op_type == IS_CONST &&
EXPECTED(Z_OBJCE_P(container) == CACHED_PTR_EX(cache_slot))) {
- uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
+ uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
zend_object *zobj = Z_OBJ_P(container);
zval *retval;
- if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
retval = OBJ_PROP(zobj, prop_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
ZVAL_INDIRECT(result, retval);
@@ -1917,11 +2226,11 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
} else if (EXPECTED(zobj->properties != NULL)) {
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
- GC_REFCOUNT(zobj->properties)--;
+ GC_DELREF(zobj->properties);
}
zobj->properties = zend_array_dup(zobj->properties);
}
- retval = zend_hash_find(zobj->properties, Z_STR_P(prop_ptr));
+ retval = zend_hash_find_ex(zobj->properties, Z_STR_P(prop_ptr), 1);
if (EXPECTED(retval)) {
ZVAL_INDIRECT(result, retval);
return;
@@ -1940,7 +2249,7 @@ use_read_property:
ZVAL_UNREF(ptr);
}
} else {
- zend_throw_error(NULL, "Cannot access undefined property for object with overloaded property access");
+ zend_access_undefined_propery_in_overloaded_object();
ZVAL_ERROR(result);
}
} else {
@@ -1949,101 +2258,47 @@ use_read_property:
} else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
goto use_read_property;
} else {
- zend_error(E_WARNING, "This object doesn't support property references");
+ zend_unsupported_property_reference();
ZVAL_ERROR(result);
}
}
-static zend_always_inline zval* zend_fetch_static_property_address(zval *varname, zend_uchar varname_type, znode_op op2, zend_uchar op2_type, int type EXECUTE_DATA_DC)
+static zend_never_inline void zend_fetch_this_var(int type OPLINE_DC EXECUTE_DATA_DC)
{
- zval *retval;
- zend_string *name;
- zend_class_entry *ce;
-
- if (varname_type == IS_CONST) {
- name = Z_STR_P(varname);
- } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) {
- name = Z_STR_P(varname);
- zend_string_addref(name);
- } else {
- if (varname_type == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
- zval_undefined_cv(EX(opline)->op1.var EXECUTE_DATA_CC);
- }
- name = zval_get_string(varname);
- }
-
- if (op2_type == IS_CONST) {
- if (varname_type == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(varname))) != NULL)) {
- retval = CACHED_PTR(Z_CACHE_SLOT_P(varname) + sizeof(void*));
-
- /* check if static properties were destoyed */
- if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
- if (type != BP_VAR_IS) {
- zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
- }
- return NULL;
- }
-
- return retval;
- } else {
- zval *class_name = EX_CONSTANT(op2);
+ zval *result = EX_VAR(opline->result.var);
- if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(class_name))) == NULL)) {
- ce = zend_fetch_class_by_name(Z_STR_P(class_name), class_name + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
- if (UNEXPECTED(ce == NULL)) {
- if (varname_type != IS_CONST) {
- zend_string_release(name);
- }
- return NULL;
- }
- CACHE_PTR(Z_CACHE_SLOT_P(class_name), ce);
- }
- }
- } else {
- if (op2_type == IS_UNUSED) {
- ce = zend_fetch_class(NULL, op2.num);
- if (UNEXPECTED(ce == NULL)) {
- if (varname_type != IS_CONST) {
- zend_string_release(name);
- }
- return NULL;
+ switch (type) {
+ case BP_VAR_R:
+ if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
+ ZVAL_OBJ(result, Z_OBJ(EX(This)));
+ Z_ADDREF_P(result);
+ } else {
+ ZVAL_NULL(result);
+ zend_error(E_NOTICE,"Undefined variable: this");
}
- } else {
- ce = Z_CE_P(EX_VAR(op2.var));
- }
- if (varname_type == IS_CONST &&
- EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(varname)) == ce)) {
- retval = CACHED_PTR(Z_CACHE_SLOT_P(varname) + sizeof(void*));
-
- /* check if static properties were destoyed */
- if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
- if (type != BP_VAR_IS) {
- zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
- }
- return NULL;
+ break;
+ case BP_VAR_IS:
+ if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
+ ZVAL_OBJ(result, Z_OBJ(EX(This)));
+ Z_ADDREF_P(result);
+ } else {
+ ZVAL_NULL(result);
}
-
- return retval;
- }
- }
-
- retval = zend_std_get_static_property(ce, name, type == BP_VAR_IS);
-
- if (varname_type != IS_CONST) {
- zend_string_release(name);
- }
-
- if (UNEXPECTED(retval == NULL)) {
- return NULL;
- }
-
- if (varname_type == IS_CONST) {
- CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(varname), ce, retval);
+ break;
+ case BP_VAR_RW:
+ case BP_VAR_W:
+ ZVAL_UNDEF(result);
+ zend_throw_error(NULL, "Cannot re-assign $this");
+ break;
+ case BP_VAR_UNSET:
+ ZVAL_UNDEF(result);
+ zend_throw_error(NULL, "Cannot unset $this");
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
}
-
- return retval;
}
+
#if ZEND_INTENSIVE_DEBUGGING
#define CHECK_SYMBOL_TABLES() \
@@ -2099,23 +2354,24 @@ ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{
static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
{
zval *cv = EX_VAR_NUM(0);
- zval *end = cv + EX(func)->op_array.last_var;
- while (EXPECTED(cv != end)) {
+ int count = EX(func)->op_array.last_var;
+ while (EXPECTED(count != 0)) {
if (Z_REFCOUNTED_P(cv)) {
zend_refcounted *r = Z_COUNTED_P(cv);
- if (!--GC_REFCOUNT(r)) {
+ if (!GC_DELREF(r)) {
ZVAL_NULL(cv);
- zval_dtor_func(r);
+ rc_dtor_func(r);
} else {
gc_check_possible_root(r);
}
}
cv++;
- }
+ count--;
+ }
}
/* }}} */
-void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
+ZEND_API void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
{
i_free_compiled_variables(execute_data);
}
@@ -2153,12 +2409,75 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
* +----------------------------------------+
*/
-static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
+static zend_never_inline void zend_copy_extra_args(EXECUTE_DATA_D)
+{
+ zend_op_array *op_array = &EX(func)->op_array;
+ uint32_t first_extra_arg = op_array->num_args;
+ uint32_t num_args = EX_NUM_ARGS();
+ zval *src;
+ size_t delta;
+ uint32_t count;
+ uint32_t type_flags = 0;
+
+ if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
+ /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ opline += first_extra_arg;
+#else
+ EX(opline) += first_extra_arg;
+#endif
+
+ }
+
+ /* move extra args into separate array after all CV and TMP vars */
+ src = EX_VAR_NUM(num_args - 1);
+ delta = op_array->last_var + op_array->T - first_extra_arg;
+ count = num_args - first_extra_arg;
+ if (EXPECTED(delta != 0)) {
+ delta *= sizeof(zval);
+ do {
+ type_flags |= Z_TYPE_INFO_P(src);
+ ZVAL_COPY_VALUE((zval*)(((char*)src) + delta), src);
+ ZVAL_UNDEF(src);
+ src--;
+ } while (--count);
+ if (Z_TYPE_INFO_REFCOUNTED(type_flags)) {
+ ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
+ }
+ } else {
+ do {
+ if (Z_REFCOUNTED_P(src)) {
+ ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
+ break;
+ }
+ src--;
+ } while (--count);
+ }
+}
+
+static zend_always_inline void zend_init_cvs(uint32_t first, uint32_t last EXECUTE_DATA_DC)
+{
+ if (EXPECTED(first < last)) {
+ uint32_t count = last - first;
+ zval *var = EX_VAR_NUM(first);
+
+ do {
+ ZVAL_UNDEF(var);
+ var++;
+ } while (--count);
+ }
+}
+
+static zend_always_inline void i_init_func_execute_data(zend_op_array *op_array, zval *return_value, zend_bool may_be_trampoline EXECUTE_DATA_DC) /* {{{ */
{
uint32_t first_extra_arg, num_args;
ZEND_ASSERT(EX(func) == (zend_function*)op_array);
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ opline = op_array->opcodes;
+#else
EX(opline) = op_array->opcodes;
+#endif
EX(call) = NULL;
EX(return_value) = return_value;
@@ -2166,55 +2485,27 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
first_extra_arg = op_array->num_args;
num_args = EX_NUM_ARGS();
if (UNEXPECTED(num_args > first_extra_arg)) {
- if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
- zval *end, *src, *dst;
- uint32_t type_flags = 0;
-
- if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
- /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
- EX(opline) += first_extra_arg;
- }
-
- /* move extra args into separate array after all CV and TMP vars */
- end = EX_VAR_NUM(first_extra_arg - 1);
- src = end + (num_args - first_extra_arg);
- dst = src + (op_array->last_var + op_array->T - first_extra_arg);
- if (EXPECTED(src != dst)) {
- do {
- type_flags |= Z_TYPE_INFO_P(src);
- ZVAL_COPY_VALUE(dst, src);
- ZVAL_UNDEF(src);
- src--;
- dst--;
- } while (src != end);
- } else {
- do {
- type_flags |= Z_TYPE_INFO_P(src);
- src--;
- } while (src != end);
- }
- ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
+ if (!may_be_trampoline || EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
+ zend_copy_extra_args(EXECUTE_DATA_C);
}
} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ opline += num_args;
+#else
EX(opline) += num_args;
+#endif
}
/* Initialize CV variables (skip arguments) */
- if (EXPECTED((int)num_args < op_array->last_var)) {
- zval *var = EX_VAR_NUM(num_args);
- zval *end = EX_VAR_NUM(op_array->last_var);
-
- do {
- ZVAL_UNDEF(var);
- var++;
- } while (var != end);
- }
+ zend_init_cvs(num_args, op_array->last_var EXECUTE_DATA_CC);
EX_LOAD_RUN_TIME_CACHE(op_array);
- EX_LOAD_LITERALS(op_array);
EG(current_execute_data) = execute_data;
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ EX(opline) = opline;
+#endif
}
/* }}} */
@@ -2226,6 +2517,64 @@ static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_arr
}
/* }}} */
+static zend_always_inline zend_function* ZEND_FASTCALL init_func_run_time_cache_i(zval *zv) /* {{{ */
+{
+ zend_op_array *op_array = Z_PTR_P(zv);
+
+ ZEND_ASSERT(op_array->run_time_cache == NULL);
+ if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) {
+ zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array) + op_array->cache_size);
+
+ Z_PTR_P(zv) = new_op_array;
+ memcpy(new_op_array, op_array, sizeof(zend_op_array));
+ new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
+ new_op_array->run_time_cache = (void**)(new_op_array + 1);
+ memset(new_op_array->run_time_cache, 0, new_op_array->cache_size);
+ return (zend_function*)new_op_array;
+ } else {
+ op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
+ memset(op_array->run_time_cache, 0, op_array->cache_size);
+ return (zend_function*)op_array;
+ }
+}
+/* }}} */
+
+static zend_never_inline zend_function* init_func_run_time_cache_ex(zval *zv) /* {{{ */
+{
+ return init_func_run_time_cache_i(zv);
+}
+/* }}} */
+
+ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
+{
+ zval *zv = zend_hash_find(EG(function_table), name);
+
+ if (EXPECTED(zv != NULL)) {
+ zend_function *fbc = Z_FUNC_P(zv);
+
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ fbc = (zend_function*)init_func_run_time_cache_i(zv);
+ }
+ return fbc;
+ }
+ return NULL;
+} /* }}} */
+
+ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
+{
+ zval *zv = zend_hash_str_find(EG(function_table), name, len);
+
+ if (EXPECTED(zv != NULL)) {
+ zend_function *fbc = Z_FUNC_P(zv);
+
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ fbc = (zend_function*)init_func_run_time_cache_i(zv);
+ }
+ return fbc;
+ }
+ return NULL;
+} /* }}} */
+
static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
{
ZEND_ASSERT(EX(func) == (zend_function*)op_array);
@@ -2241,20 +2590,32 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
memset(op_array->run_time_cache, 0, op_array->cache_size);
}
EX_LOAD_RUN_TIME_CACHE(op_array);
- EX_LOAD_LITERALS(op_array);
EG(current_execute_data) = execute_data;
}
/* }}} */
-ZEND_API void zend_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
+ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array *op_array, zval *return_value) /* {{{ */
{
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ zend_execute_data *orig_execute_data = execute_data;
+ const zend_op *orig_opline = opline;
+ execute_data = ex;
+#else
+ zend_execute_data *execute_data = ex;
+#endif
+
EX(prev_execute_data) = EG(current_execute_data);
if (!op_array->run_time_cache) {
- op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
- memset(op_array->run_time_cache, 0, op_array->cache_size);
+ init_func_run_time_cache(op_array);
}
- i_init_func_execute_data(execute_data, op_array, return_value);
+ i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC);
+
+#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
+ EX(opline) = opline;
+ opline = orig_opline;
+ execute_data = orig_execute_data;
+#endif
}
/* }}} */
@@ -2279,14 +2640,12 @@ ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_ar
}
/* }}} */
-static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(const zend_op *opline, zend_execute_data *call) /* {{{ */
+static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(uint32_t arg_num, zend_function *func) /* {{{ */
{
- uint32_t arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK;
-
if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
- return QUICK_ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
+ return QUICK_ARG_SHOULD_BE_SENT_BY_REF(func, arg_num);
}
- return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
+ return ARG_SHOULD_BE_SENT_BY_REF(func, arg_num);
}
/* }}} */
@@ -2399,6 +2758,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
case ZEND_SEND_VAL_EX:
case ZEND_SEND_VAR:
case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
case ZEND_SEND_REF:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
@@ -2453,7 +2813,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) {
- GC_REFCOUNT(Z_OBJ(call->This))--;
+ GC_DELREF(Z_OBJ(call->This));
if (GC_REFCOUNT(Z_OBJ(call->This)) == 1) {
zend_object_store_ctor_failed(Z_OBJ(call->This));
}
@@ -2461,9 +2821,9 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
OBJ_RELEASE(Z_OBJ(call->This));
}
if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
- zend_object_release((zend_object *) call->func->common.prototype);
+ zend_object_release(ZEND_CLOSURE_OBJECT(call->func));
} else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
- zend_string_release(call->func->common.function_name);
+ zend_string_release_ex(call->func->common.function_name, 0);
zend_free_trampoline(call->func);
}
@@ -2475,6 +2835,20 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
}
/* }}} */
+static const zend_live_range *find_live_range(const zend_op_array *op_array, uint32_t op_num, uint32_t var_num) /* {{{ */
+{
+ int i;
+ for (i = 0; i < op_array->last_live_range; i++) {
+ const zend_live_range *range = &op_array->live_range[i];
+ if (op_num >= range->start && op_num < range->end
+ && var_num == (range->var & ~ZEND_LIVE_MASK)) {
+ return range;
+ }
+ }
+ return NULL;
+}
+/* }}} */
+
static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
{
int i;
@@ -2506,11 +2880,11 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
last--;
}
if (last->opcode == ZEND_ROPE_INIT) {
- zend_string_release(*rope);
+ zend_string_release_ex(*rope, 0);
} else {
int j = last->extended_value;
do {
- zend_string_release(rope[j]);
+ zend_string_release_ex(rope[j], 0);
} while (j--);
}
} else if (kind == ZEND_LIVE_SILENCE) {
@@ -2525,7 +2899,7 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
}
/* }}} */
-void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
+ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
cleanup_unfinished_calls(execute_data, op_num);
cleanup_live_vars(execute_data, op_num, catch_op_num);
}
@@ -2564,7 +2938,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(called_scope == NULL)) {
- zend_string_release(lcname);
+ zend_string_release_ex(lcname, 0);
return NULL;
}
@@ -2577,32 +2951,25 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
}
if (UNEXPECTED(fbc == NULL)) {
if (EXPECTED(!EG(exception))) {
- zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(called_scope->name), ZSTR_VAL(mname));
+ zend_undefined_method(called_scope, mname);
}
- zend_string_release(lcname);
- zend_string_release(mname);
+ zend_string_release_ex(lcname, 0);
+ zend_string_release_ex(mname, 0);
return NULL;
}
- zend_string_release(lcname);
- zend_string_release(mname);
+ zend_string_release_ex(lcname, 0);
+ zend_string_release_ex(mname, 0);
if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
- if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
- zend_error(E_DEPRECATED,
- "Non-static method %s::%s() should not be called statically",
- ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
- if (UNEXPECTED(EG(exception) != NULL)) {
- return NULL;
- }
- } else {
- zend_throw_error(
- zend_ce_error,
- "Non-static method %s::%s() cannot be called statically",
- ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ zend_non_static_method_call(fbc);
+ if (UNEXPECTED(EG(exception) != NULL)) {
return NULL;
}
}
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
} else {
if (ZSTR_VAL(function)[0] == '\\') {
lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
@@ -2612,19 +2979,18 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
}
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
- zend_string_release(lcname);
+ zend_string_release_ex(lcname, 0);
return NULL;
}
- zend_string_release(lcname);
+ zend_string_release_ex(lcname, 0);
fbc = Z_FUNC_P(func);
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ fbc = init_func_run_time_cache_ex(func);
+ }
called_scope = NULL;
}
- if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
- init_func_run_time_cache(&fbc->op_array);
- }
-
return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC,
fbc, num_args, called_scope, NULL);
}
@@ -2642,15 +3008,14 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
/* Delay closure destruction until its invocation */
- ZEND_ASSERT(GC_TYPE((zend_object*)fbc->common.prototype) == IS_OBJECT);
- GC_REFCOUNT((zend_object*)fbc->common.prototype)++;
+ GC_ADDREF(ZEND_CLOSURE_OBJECT(fbc));
call_info |= ZEND_CALL_CLOSURE;
if (fbc->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
call_info |= ZEND_CALL_FAKE_CLOSURE;
}
} else if (object) {
call_info |= ZEND_CALL_RELEASE_THIS;
- GC_REFCOUNT(object)++; /* For $this pointer */
+ GC_ADDREF(object); /* For $this pointer */
}
} else {
zend_throw_error(NULL, "Function name must be a string");
@@ -2710,23 +3075,13 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
}
if (UNEXPECTED(fbc == NULL)) {
if (EXPECTED(!EG(exception))) {
- zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(called_scope->name), Z_STRVAL_P(method));
+ zend_undefined_method(called_scope, Z_STR_P(method));
}
return NULL;
}
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
- if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
- zend_error(E_DEPRECATED,
- "Non-static method %s::%s() should not be called statically",
- ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
- if (UNEXPECTED(EG(exception) != NULL)) {
- return NULL;
- }
- } else {
- zend_throw_error(
- zend_ce_error,
- "Non-static method %s::%s() cannot be called statically",
- ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ zend_non_static_method_call(fbc);
+ if (UNEXPECTED(EG(exception) != NULL)) {
return NULL;
}
}
@@ -2737,7 +3092,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
if (UNEXPECTED(fbc == NULL)) {
if (EXPECTED(!EG(exception))) {
- zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(object->ce->name), Z_STRVAL_P(method));
+ zend_undefined_method(object->ce, Z_STR_P(method));
}
return NULL;
}
@@ -2746,7 +3101,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
object = NULL;
} else {
call_info |= ZEND_CALL_RELEASE_THIS;
- GC_REFCOUNT(object)++; /* For $this pointer */
+ GC_ADDREF(object); /* For $this pointer */
}
}
} else {
@@ -2772,76 +3127,81 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval
ZVAL_UNDEF(&tmp_inc_filename);
if (Z_TYPE_P(inc_filename) != IS_STRING) {
- ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename));
+ ZVAL_STR(&tmp_inc_filename, zval_get_string_func(inc_filename));
inc_filename = &tmp_inc_filename;
}
- if (type != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) {
- if (type == ZEND_INCLUDE_ONCE || type == ZEND_INCLUDE) {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
- }
- } else {
- switch (type) {
- case ZEND_INCLUDE_ONCE:
- case ZEND_REQUIRE_ONCE: {
- zend_file_handle file_handle;
- zend_string *resolved_path;
-
- resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename));
- if (resolved_path) {
- if (zend_hash_exists(&EG(included_files), resolved_path)) {
- goto already_compiled;
- }
- } else {
- resolved_path = zend_string_copy(Z_STR_P(inc_filename));
+ switch (type) {
+ case ZEND_INCLUDE_ONCE:
+ case ZEND_REQUIRE_ONCE: {
+ zend_file_handle file_handle;
+ zend_string *resolved_path;
+
+ resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+ if (EXPECTED(resolved_path)) {
+ if (zend_hash_exists(&EG(included_files), resolved_path)) {
+ goto already_compiled;
}
+ } else if (UNEXPECTED(strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename))) {
+ zend_message_dispatcher(
+ (type == ZEND_INCLUDE_ONCE) ?
+ ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
+ Z_STRVAL_P(inc_filename));
+ break;
+ } else {
+ resolved_path = zend_string_copy(Z_STR_P(inc_filename));
+ }
- if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) {
+ if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) {
- if (!file_handle.opened_path) {
- file_handle.opened_path = zend_string_copy(resolved_path);
- }
+ if (!file_handle.opened_path) {
+ file_handle.opened_path = zend_string_copy(resolved_path);
+ }
- if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) {
- zend_op_array *op_array = zend_compile_file(&file_handle, (type==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE));
- zend_destroy_file_handle(&file_handle);
- zend_string_release(resolved_path);
- if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) {
- zend_string_release(Z_STR(tmp_inc_filename));
- }
- return op_array;
- } else {
- zend_file_handle_dtor(&file_handle);
-already_compiled:
- new_op_array = ZEND_FAKE_OP_ARRAY;
+ if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) {
+ zend_op_array *op_array = zend_compile_file(&file_handle, (type==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE));
+ zend_destroy_file_handle(&file_handle);
+ zend_string_release_ex(resolved_path, 0);
+ if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) {
+ zval_ptr_dtor_str(&tmp_inc_filename);
}
+ return op_array;
} else {
- if (type == ZEND_INCLUDE_ONCE) {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
- }
+ zend_file_handle_dtor(&file_handle);
+already_compiled:
+ new_op_array = ZEND_FAKE_OP_ARRAY;
}
- zend_string_release(resolved_path);
- }
- break;
- case ZEND_INCLUDE:
- case ZEND_REQUIRE:
- new_op_array = compile_filename(type, inc_filename);
- break;
- case ZEND_EVAL: {
- char *eval_desc = zend_make_compiled_string_description("eval()'d code");
- new_op_array = zend_compile_string(inc_filename, eval_desc);
- efree(eval_desc);
+ } else {
+ zend_message_dispatcher(
+ (type == ZEND_INCLUDE_ONCE) ?
+ ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
+ Z_STRVAL_P(inc_filename));
}
+ zend_string_release_ex(resolved_path, 0);
+ }
+ break;
+ case ZEND_INCLUDE:
+ case ZEND_REQUIRE:
+ if (UNEXPECTED(strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename))) {
+ zend_message_dispatcher(
+ (type == ZEND_INCLUDE) ?
+ ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
+ Z_STRVAL_P(inc_filename));
break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
+ }
+ new_op_array = compile_filename(type, inc_filename);
+ break;
+ case ZEND_EVAL: {
+ char *eval_desc = zend_make_compiled_string_description("eval()'d code");
+ new_op_array = zend_compile_string(inc_filename, eval_desc);
+ efree(eval_desc);
+ }
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
}
+
if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) {
- zend_string_release(Z_STR(tmp_inc_filename));
+ zval_ptr_dtor_str(&tmp_inc_filename);
}
return new_op_array;
}
@@ -2856,7 +3216,7 @@ ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zva
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
- zend_string_release(fbc->common.function_name);
+ zend_string_release_ex(fbc->common.function_name, 0);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
@@ -2876,7 +3236,7 @@ ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zva
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
- zend_string_release(fbc->common.function_name);
+ zend_string_release_ex(fbc->common.function_name, 0);
}
efree(fbc);
@@ -2884,6 +3244,168 @@ ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zva
}
/* }}} */
+static zend_never_inline zend_bool ZEND_FASTCALL zend_fe_reset_iterator(zval *array_ptr, int by_ref OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+ zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+ zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, by_ref);
+ zend_bool is_empty;
+
+ if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+ if (iter) {
+ OBJ_RELEASE(&iter->std);
+ }
+ if (!EG(exception)) {
+ zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ZSTR_VAL(ce->name));
+ }
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ return 1;
+ }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ OBJ_RELEASE(&iter->std);
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ return 1;
+ }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ OBJ_RELEASE(&iter->std);
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ return 1;
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+ return is_empty;
+}
+/* }}} */
+
+static zend_always_inline int _zend_quick_get_constant(
+ const zval *key, uint32_t flags, int check_defined_only OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+ zval *zv;
+ const zval *orig_key = key;
+ zend_constant *c = NULL;
+
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ } else {
+ key++;
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv && (ZEND_CONSTANT_FLAGS((zend_constant*)Z_PTR_P(zv)) & CONST_CS) == 0) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ } else {
+ if ((flags & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
+ key++;
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ } else {
+ key++;
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv && (ZEND_CONSTANT_FLAGS((zend_constant*)Z_PTR_P(zv)) & CONST_CS) == 0) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ }
+ }
+ }
+ }
+ }
+
+ if (!c) {
+ if (!check_defined_only) {
+ if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
+ char *actual = (char *)zend_memrchr(Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)), '\\', Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)));
+ if (!actual) {
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+ } else {
+ actual++;
+ ZVAL_STRINGL(EX_VAR(opline->result.var),
+ actual, Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)) - (actual - Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))));
+ }
+ /* non-qualified constant - allow text substitution */
+ zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)",
+ Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
+ } else {
+ zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ }
+ }
+ return FAILURE;
+ }
+
+ if (!check_defined_only) {
+ ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
+ if (!(ZEND_CONSTANT_FLAGS(c) & (CONST_CS|CONST_CT_SUBST))) {
+ const char *ns_sep;
+ size_t shortname_offset;
+ size_t shortname_len;
+ zend_bool is_deprecated;
+
+ if (flags & IS_CONSTANT_UNQUALIFIED) {
+ const zval *access_key;
+
+ if (!(flags & IS_CONSTANT_IN_NAMESPACE)) {
+ access_key = orig_key - 1;
+ } else {
+ if (key < orig_key + 2) {
+ goto check_short_name;
+ } else {
+ access_key = orig_key + 2;
+ }
+ }
+ is_deprecated = !zend_string_equals(c->name, Z_STR_P(access_key));
+ } else {
+check_short_name:
+ ns_sep = zend_memrchr(ZSTR_VAL(c->name), '\\', ZSTR_LEN(c->name));
+ ZEND_ASSERT(ns_sep);
+ /* Namespaces are always case-insensitive. Only compare shortname. */
+ shortname_offset = ns_sep - ZSTR_VAL(c->name) + 1;
+ shortname_len = ZSTR_LEN(c->name) - shortname_offset;
+
+ is_deprecated = memcmp(ZSTR_VAL(c->name) + shortname_offset, Z_STRVAL_P(orig_key - 1) + shortname_offset, shortname_len) != 0;
+ }
+
+ if (is_deprecated) {
+ zend_error(E_DEPRECATED,
+ "Case-insensitive constants are deprecated. "
+ "The correct casing for this constant is \"%s\"",
+ ZSTR_VAL(c->name));
+ return SUCCESS;
+ }
+ }
+ }
+
+ CACHE_PTR(opline->extended_value, c);
+ return SUCCESS;
+}
+/* }}} */
+
+static zend_never_inline void ZEND_FASTCALL zend_quick_get_constant(
+ const zval *key, uint32_t flags OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+ _zend_quick_get_constant(key, flags, 0 OPLINE_CC EXECUTE_DATA_CC);
+} /* }}} */
+
+static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant(
+ const zval *key OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+ return _zend_quick_get_constant(key, 0, 1 OPLINE_CC EXECUTE_DATA_CC);
+} /* }}} */
+
+#ifdef ZEND_VM_TRACE_HANDLERS
+# include "zend_vm_trace_handlers.h"
+#elif defined(ZEND_VM_TRACE_MAP)
+# include "zend_vm_trace_map.h"
+#endif
+
#define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
CHECK_SYMBOL_TABLES() \
if (check_exception) { \
@@ -2911,14 +3433,17 @@ ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zva
#define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
ZEND_VM_SET_OPCODE(ZEND_OFFSET_TO_OPLINE(opline, offset))
-#define ZEND_VM_JMP(new_op) do { \
- if (UNEXPECTED(EG(exception))) { \
+#define ZEND_VM_JMP_EX(new_op, check_exception) do { \
+ if (check_exception && UNEXPECTED(EG(exception))) { \
HANDLE_EXCEPTION(); \
} \
ZEND_VM_SET_OPCODE(new_op); \
ZEND_VM_CONTINUE(); \
} while (0)
+#define ZEND_VM_JMP(new_op) \
+ ZEND_VM_JMP_EX(new_op, 1)
+
#define ZEND_VM_INC_OPCODE() \
OPLINE++
@@ -3003,8 +3528,18 @@ ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zva
} \
} while (0)
+#if ZEND_GCC_VERSION >= 4000 && !defined(__clang__)
+# pragma GCC push_options
+# pragma GCC optimize("no-gcse")
+# pragma GCC optimize("no-ivopts")
+#endif
+
#include "zend_vm_execute.h"
+#if ZEND_GCC_VERSION >= 4000 && !defined(__clang__)
+# pragma GCC pop_options
+#endif
+
ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
{
if (opcode != ZEND_USER_OPCODE) {
@@ -3025,13 +3560,13 @@ ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
return zend_user_opcode_handlers[opcode];
}
-ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
+ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
{
zval *ret;
switch (op_type) {
case IS_CONST:
- ret = EX_CONSTANT(*node);
+ ret = RT_CONSTANT(opline, *node);
*should_free = NULL;
break;
case IS_TMP_VAR: