summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_def.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_vm_def.h')
-rw-r--r--Zend/zend_vm_def.h2536
1 files changed, 1456 insertions, 1080 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index de67318bed..4742a62b58 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -290,7 +290,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
!ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
size_t len = ZSTR_LEN(op1_str);
- str = zend_string_realloc(op1_str, len + ZSTR_LEN(op2_str), 0);
+ str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0);
memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1);
ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
break;
@@ -711,7 +711,7 @@ ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
SAVE_OPLINE();
object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(object) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var);
FREE_UNFETCHED_OP2();
@@ -737,13 +737,18 @@ ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
/* here we are sure we are dealing with an object */
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
+ if (UNEXPECTED(Z_ISERROR_P(zptr))) {
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
+ }
+ } else {
+ ZVAL_DEREF(zptr);
+ SEPARATE_ZVAL_NOREF(zptr);
- ZVAL_DEREF(zptr);
- SEPARATE_ZVAL_NOREF(zptr);
-
- binary_op(zptr, zptr, value);
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_COPY(EX_VAR(opline->result.var), zptr);
+ binary_op(zptr, zptr, value);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), zptr);
+ }
}
} else {
zend_assign_op_overloaded_property(object, property, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), value, binary_op, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL));
@@ -757,56 +762,89 @@ ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
ZEND_VM_NEXT_OPCODE_EX(1, 2);
}
-ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV, binary_op_type binary_op)
+ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|CV, CONST|TMPVAR|UNUSED|CV, binary_op_type binary_op)
{
USE_OPLINE
zend_free_op free_op1, free_op2, free_op_data1;
- zval *var_ptr, rv;
+ zval *var_ptr;
zval *value, *container, *dim;
SAVE_OPLINE();
- container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
- zend_throw_error(NULL, "Using $this when not in object context");
- FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var);
- FREE_UNFETCHED_OP2();
- HANDLE_EXCEPTION();
- }
+ container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
- dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ZEND_VM_C_LABEL(assign_dim_op_array):
+ SEPARATE_ARRAY(container);
+ZEND_VM_C_LABEL(assign_dim_op_new_array):
+ if (OP2_TYPE == IS_UNUSED) {
+ var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
+ if (UNEXPECTED(!var_ptr)) {
+ zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
+ ZEND_VM_C_GOTO(assign_dim_op_ret_null);
+ }
+ } else {
+ dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
- do {
- if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) {
- if (OP1_TYPE != IS_UNUSED) {
- ZVAL_DEREF(container);
+ if (OP2_TYPE == IS_CONST) {
+ var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim);
+ } else {
+ var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim);
}
- if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
- value = get_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1);
- zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op);
- break;
+ if (UNEXPECTED(!var_ptr)) {
+ ZEND_VM_C_GOTO(assign_dim_op_ret_null);
}
+ ZVAL_DEREF(var_ptr);
+ SEPARATE_ZVAL_NOREF(var_ptr);
}
- zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE);
value = get_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1);
- if (UNEXPECTED(Z_ISERROR(rv))) {
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_NULL(EX_VAR(opline->result.var));
+ binary_op(var_ptr, var_ptr, value);
+
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
+ }
+ } else {
+ if (EXPECTED(Z_ISREF_P(container))) {
+ container = Z_REFVAL_P(container);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ ZEND_VM_C_GOTO(assign_dim_op_array);
}
- } else {
- ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT);
- var_ptr = Z_INDIRECT(rv);
- ZVAL_DEREF(var_ptr);
- SEPARATE_ZVAL_NOREF(var_ptr);
+ } else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) {
+ container = GET_OP1_UNDEF_CV(container, BP_VAR_RW);
+ZEND_VM_C_LABEL(assign_dim_op_convert_to_array):
+ ZVAL_NEW_ARR(container);
+ zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
+ ZEND_VM_C_GOTO(assign_dim_op_new_array);
+ }
- binary_op(var_ptr, var_ptr, value);
+ dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
+ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ value = get_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1);
+ zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op);
+ } else {
+ if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
+ if (OP2_TYPE == IS_UNUSED) {
+ zend_throw_error(NULL, "[] operator not supported for strings");
+ } else {
+ zend_check_string_offset(dim, BP_VAR_RW);
+ zend_wrong_string_offset();
+ }
+ } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
+ ZEND_VM_C_GOTO(assign_dim_op_convert_to_array);
+ } else {
+ if (UNEXPECTED(OP1_TYPE != IS_VAR || EXPECTED(!Z_ISERROR_P(container)))) {
+ zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ }
+ZEND_VM_C_LABEL(assign_dim_op_ret_null):
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
+ }
}
+ value = get_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1);
}
- } while (0);
+ }
FREE_OP2();
FREE_OP(free_op_data1);
@@ -845,7 +883,7 @@ ZEND_VM_HELPER(zend_binary_assign_op_helper, VAR|CV, CONST|TMPVAR|CV, binary_op_
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -854,18 +892,17 @@ ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, add_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, add_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, add_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, add_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, add_function);
#endif
}
-ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -874,18 +911,17 @@ ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, sub_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, sub_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, sub_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, sub_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, sub_function);
#endif
}
-ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -894,18 +930,17 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mul_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mul_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mul_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mul_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mul_function);
#endif
}
-ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -914,18 +949,17 @@ ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, div_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, div_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, div_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, div_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, div_function);
#endif
}
-ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -934,18 +968,17 @@ ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mod_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mod_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mod_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mod_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mod_function);
#endif
}
-ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -954,18 +987,17 @@ ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_left_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_left_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_left_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_left_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_left_function);
#endif
}
-ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -974,18 +1006,17 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_right_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_right_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_right_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_right_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_right_function);
#endif
}
-ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -994,18 +1025,17 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, concat_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, concat_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, concat_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, concat_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, concat_function);
#endif
}
-ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -1014,18 +1044,17 @@ ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|N
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_or_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_or_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_or_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_or_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_or_function);
#endif
}
-ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -1034,18 +1063,17 @@ ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_and_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_and_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_and_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_and_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_and_function);
#endif
}
-ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -1054,18 +1082,17 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_xor_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_xor_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_xor_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_xor_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_xor_function);
#endif
}
-ZEND_VM_HANDLER(167, ZEND_ASSIGN_POW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ)
+ZEND_VM_HANDLER(167, ZEND_ASSIGN_POW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT|CV, DIM_OBJ, SPEC(DIM_OBJ))
{
#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED)
USE_OPLINE
@@ -1074,12 +1101,11 @@ ZEND_VM_HANDLER(167, ZEND_ASSIGN_POW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NE
if (EXPECTED(opline->extended_value == 0)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, pow_function);
}
-# endif
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, pow_function);
- } else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
- ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, pow_function);
}
+# endif
+ ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, pow_function);
#else
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, pow_function);
#endif
@@ -1096,7 +1122,7 @@ ZEND_VM_HELPER(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
SAVE_OPLINE();
object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(object) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -1117,28 +1143,32 @@ ZEND_VM_HELPER(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
}
/* here we are sure we are dealing with an object */
-
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
-
- if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) {
- if (inc) {
- fast_long_increment_function(zptr);
- } else {
- fast_long_decrement_function(zptr);
+ if (UNEXPECTED(Z_ISERROR_P(zptr))) {
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
}
} else {
- ZVAL_DEREF(zptr);
- SEPARATE_ZVAL_NOREF(zptr);
-
- if (inc) {
- increment_function(zptr);
+ if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) {
+ if (inc) {
+ fast_long_increment_function(zptr);
+ } else {
+ fast_long_decrement_function(zptr);
+ }
} else {
- decrement_function(zptr);
+ ZVAL_DEREF(zptr);
+ SEPARATE_ZVAL_NOREF(zptr);
+
+ if (inc) {
+ increment_function(zptr);
+ } else {
+ decrement_function(zptr);
+ }
+ }
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), zptr);
}
- }
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_COPY(EX_VAR(opline->result.var), zptr);
}
} else {
zend_pre_incdec_overloaded_property(object, property, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), inc, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL));
@@ -1171,7 +1201,7 @@ ZEND_VM_HELPER(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
SAVE_OPLINE();
object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(object) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -1193,22 +1223,25 @@ ZEND_VM_HELPER(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
-
- if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) {
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), zptr);
- if (inc) {
- fast_long_increment_function(zptr);
- } else {
- fast_long_decrement_function(zptr);
- }
+ if (UNEXPECTED(Z_ISERROR_P(zptr))) {
+ ZVAL_NULL(EX_VAR(opline->result.var));
} else {
- ZVAL_DEREF(zptr);
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), zptr);
- zval_opt_copy_ctor(zptr);
- if (inc) {
- increment_function(zptr);
+ if (EXPECTED(Z_TYPE_P(zptr) == IS_LONG)) {
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), zptr);
+ if (inc) {
+ fast_long_increment_function(zptr);
+ } else {
+ fast_long_decrement_function(zptr);
+ }
} else {
- decrement_function(zptr);
+ ZVAL_DEREF(zptr);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), zptr);
+ zval_opt_copy_ctor(zptr);
+ if (inc) {
+ increment_function(zptr);
+ } else {
+ decrement_function(zptr);
+ }
}
}
} else {
@@ -1434,6 +1467,43 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type)
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
retval = zend_hash_find(target_symbol_table, name);
if (retval == NULL) {
+ if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) {
+ zval *result;
+
+ZEND_VM_C_LABEL(fetch_this):
+ result = EX_VAR(opline->result.var);
+ 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");
+ }
+ 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);
+ }
+ break;
+ case BP_VAR_RW:
+ case BP_VAR_W:
+ zend_throw_error(NULL, "Cannot re-assign $this");
+ break;
+ case BP_VAR_UNSET:
+ zend_throw_error(NULL, "Cannot unset $this");
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+ if (OP1_TYPE != IS_CONST) {
+ zend_string_release(name);
+ }
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+ }
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
@@ -1455,6 +1525,9 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type)
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
retval = Z_INDIRECT_P(retval);
if (Z_TYPE_P(retval) == IS_UNDEF) {
+ if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) {
+ ZEND_VM_C_GOTO(fetch_this);
+ }
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
@@ -1675,11 +1748,33 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
- zval *container;
+ zval *container, *dim, *value, *result;
SAVE_OPLINE();
- container = GET_OP1_ZVAL_PTR(BP_VAR_R);
- zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ if (OP1_TYPE != IS_CONST) {
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ZEND_VM_C_LABEL(fetch_dim_r_array):
+ value = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, OP2_TYPE, BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_COPY(result, value);
+ } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
+ container = Z_REFVAL_P(container);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ ZEND_VM_C_GOTO(fetch_dim_r_array);
+ } else {
+ ZEND_VM_C_GOTO(fetch_dim_r_slow);
+ }
+ } else {
+ZEND_VM_C_LABEL(fetch_dim_r_slow):
+ result = EX_VAR(opline->result.var);
+ zend_fetch_dimension_address_read_R_slow(result, container, dim);
+ }
+ } else {
+ result = EX_VAR(opline->result.var);
+ zend_fetch_dimension_address_read_R(result, container, dim, OP2_TYPE);
+ }
FREE_OP2();
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -1694,7 +1789,7 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV)
SAVE_OPLINE();
container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@@ -1710,9 +1805,9 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV)
zval *container;
SAVE_OPLINE();
- container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
+ container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
- zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@@ -1728,8 +1823,8 @@ ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
zval *container;
SAVE_OPLINE();
- container = GET_OP1_ZVAL_PTR(BP_VAR_IS);
- zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_IS);
+ zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
FREE_OP2();
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -1751,7 +1846,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS
HANDLE_EXCEPTION();
}
container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
}
@@ -1764,8 +1859,8 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS
FREE_UNFETCHED_OP1();
HANDLE_EXCEPTION();
}
- container = GET_OP1_ZVAL_PTR(BP_VAR_R);
- zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
FREE_OP2();
FREE_OP1();
}
@@ -1779,9 +1874,9 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMPVAR|CV)
zval *container;
SAVE_OPLINE();
- container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_UNSET);
+ container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
- zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE);
+ zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R), OP2_TYPE);
FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@@ -1801,7 +1896,7 @@ ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -1874,7 +1969,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_OP2();
HANDLE_EXCEPTION();
@@ -1900,7 +1995,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_OP2();
HANDLE_EXCEPTION();
@@ -1925,7 +2020,7 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -2001,7 +2096,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THIS|CV, CONST
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_OP2();
HANDLE_EXCEPTION();
@@ -2033,7 +2128,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -2050,47 +2145,16 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST)
+ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
- zend_free_op free_op1;
+ zend_free_op free_op1, free_op2;
zval *container;
SAVE_OPLINE();
container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
-
-ZEND_VM_C_LABEL(try_fetch_list):
- if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
- zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2)));
-
- if (UNEXPECTED(value == NULL)) {
- zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2)));
- ZVAL_NULL(EX_VAR(opline->result.var));
- } else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- }
- } else if (OP1_TYPE != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
- EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
- zval *result = EX_VAR(opline->result.var);
- zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result);
-
- if (retval) {
- if (result != retval) {
- ZVAL_COPY(result, retval);
- }
- } else {
- ZVAL_NULL(result);
- }
- } else if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
- container = Z_REFVAL_P(container);
- ZEND_VM_C_GOTO(try_fetch_list);
- } else {
- if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
- GET_OP1_UNDEF_CV(container, BP_VAR_R);
- }
- ZVAL_NULL(EX_VAR(opline->result.var));
- }
+ zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R));
+ FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
@@ -2103,7 +2167,7 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, SPEC(
SAVE_OPLINE();
object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(object) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -2114,13 +2178,6 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, SPEC(
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
do {
- if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(object))) {
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_NULL(EX_VAR(opline->result.var));
- }
- FREE_OP_DATA();
- ZEND_VM_C_GOTO(exit_assign_obj);
- }
if (Z_ISREF_P(object)) {
object = Z_REFVAL_P(object);
if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
@@ -2147,7 +2204,9 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, SPEC(
}
Z_DELREF_P(object);
} else {
- zend_error(E_WARNING, "Attempt to assign property of non-object");
+ if (OP1_TYPE != IS_VAR || EXPECTED(!Z_ISERROR_P(object))) {
+ zend_error(E_WARNING, "Attempt to assign property of non-object");
+ }
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
@@ -2192,12 +2251,9 @@ ZEND_VM_C_LABEL(fast_assign_obj):
if (EXPECTED(zobj->properties == NULL)) {
rebuild_object_properties(zobj);
}
- /* separate our value if necessary */
if (OP_DATA_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- ZVAL_COPY_VALUE(&tmp, value);
- zval_copy_ctor_func(&tmp);
- value = &tmp;
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(value))) {
+ Z_ADDREF_P(value);
}
} else if (OP_DATA_TYPE != IS_TMP_VAR) {
if (Z_ISREF_P(value)) {
@@ -2241,14 +2297,7 @@ ZEND_VM_C_LABEL(fast_assign_obj):
ZEND_VM_C_GOTO(exit_assign_obj);
}
- /* separate our value if necessary */
- if (OP_DATA_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- ZVAL_COPY_VALUE(&tmp, value);
- zval_copy_ctor_func(&tmp);
- value = &tmp;
- }
- } else if (OP_DATA_TYPE != IS_TMP_VAR) {
+ if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) {
ZVAL_DEREF(value);
}
@@ -2257,11 +2306,7 @@ ZEND_VM_C_LABEL(fast_assign_obj):
if (UNEXPECTED(RETURN_VALUE_USED(opline)) && EXPECTED(!EG(exception))) {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
- if (OP_DATA_TYPE == IS_CONST) {
- zval_ptr_dtor_nogc(value);
- } else {
- FREE_OP_DATA();
- }
+ FREE_OP_DATA();
ZEND_VM_C_LABEL(exit_assign_obj):
FREE_OP2();
FREE_OP1_VAR_PTR();
@@ -2284,31 +2329,29 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) {
ZEND_VM_C_LABEL(try_assign_dim_array):
+ SEPARATE_ARRAY(object_ptr);
if (OP2_TYPE == IS_UNUSED) {
- SEPARATE_ARRAY(object_ptr);
variable_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(object_ptr), &EG(uninitialized_zval));
if (UNEXPECTED(variable_ptr == NULL)) {
zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
- variable_ptr = NULL;
+ ZEND_VM_C_GOTO(assign_dim_error);
}
} else {
- dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
- SEPARATE_ARRAY(object_ptr);
- variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, OP2_TYPE, BP_VAR_W);
- FREE_OP2();
- }
- if (UNEXPECTED(variable_ptr == NULL)) {
- FREE_UNFETCHED_OP_DATA();
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_NULL(EX_VAR(opline->result.var));
+ dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ if (OP2_TYPE == IS_CONST) {
+ variable_ptr = zend_fetch_dimension_address_inner_W_CONST(Z_ARRVAL_P(object_ptr), dim);
+ } else {
+ variable_ptr = zend_fetch_dimension_address_inner_W(Z_ARRVAL_P(object_ptr), dim);
}
- } else {
- value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);
- value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
- if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (UNEXPECTED(variable_ptr == NULL)) {
+ ZEND_VM_C_GOTO(assign_dim_error);
}
}
+ value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);
+ value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ }
} else {
if (EXPECTED(Z_ISREF_P(object_ptr))) {
object_ptr = Z_REFVAL_P(object_ptr);
@@ -2317,49 +2360,47 @@ ZEND_VM_C_LABEL(try_assign_dim_array):
}
}
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
- zend_free_op free_op2;
- zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);
- zend_assign_to_object_dim(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object_ptr, property_name, OP_DATA_TYPE, (opline+1)->op1, execute_data);
- FREE_OP2();
- } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
- if (EXPECTED(Z_STRLEN_P(object_ptr) != 0)) {
- if (OP2_TYPE == IS_UNUSED) {
- zend_throw_error(NULL, "[] operator not supported for strings");
- FREE_UNFETCHED_OP_DATA();
- FREE_OP1_VAR_PTR();
- HANDLE_EXCEPTION();
- } else {
- zend_long offset;
+ zend_assign_to_object_dim(object_ptr, dim, value);
- dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
- offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W);
- FREE_OP2();
- value = GET_OP_DATA_ZVAL_PTR_DEREF(BP_VAR_R);
- zend_assign_to_string_offset(object_ptr, offset, value, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL));
- FREE_OP_DATA();
- }
+ if (UNEXPECTED(RETURN_VALUE_USED(opline)) && EXPECTED(!EG(exception))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ }
+
+ FREE_OP_DATA();
+ } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
+ if (OP2_TYPE == IS_UNUSED) {
+ zend_throw_error(NULL, "[] operator not supported for strings");
+ FREE_UNFETCHED_OP_DATA();
+ FREE_OP1_VAR_PTR();
+ HANDLE_EXCEPTION();
} else {
- zval_ptr_dtor_nogc(object_ptr);
-ZEND_VM_C_LABEL(assign_dim_convert_to_array):
- ZVAL_NEW_ARR(object_ptr);
- zend_hash_init(Z_ARRVAL_P(object_ptr), 8, NULL, ZVAL_PTR_DTOR, 0);
- ZEND_VM_C_GOTO(try_assign_dim_array);
+ dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ value = GET_OP_DATA_ZVAL_PTR_DEREF(BP_VAR_R);
+ zend_assign_to_string_offset(object_ptr, dim, value, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL));
+ FREE_OP_DATA();
}
} else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) {
- ZEND_VM_C_GOTO(assign_dim_convert_to_array);
- } else if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(object_ptr))) {
- ZEND_VM_C_GOTO(assign_dim_clean);
+ ZVAL_NEW_ARR(object_ptr);
+ zend_hash_init(Z_ARRVAL_P(object_ptr), 8, NULL, ZVAL_PTR_DTOR, 0);
+ ZEND_VM_C_GOTO(try_assign_dim_array);
} else {
- zend_error(E_WARNING, "Cannot use a scalar value as an array");
-ZEND_VM_C_LABEL(assign_dim_clean):
- FREE_UNFETCHED_OP2();
+ if (OP1_TYPE != IS_VAR || EXPECTED(!Z_ISERROR_P(object_ptr))) {
+ zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ }
+ dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ZEND_VM_C_LABEL(assign_dim_error):
FREE_UNFETCHED_OP_DATA();
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
}
}
+ if (OP2_TYPE != IS_UNUSED) {
+ FREE_OP2();
+ }
FREE_OP1_VAR_PTR();
/* assign_dim has two opcodes! */
ZEND_VM_NEXT_OPCODE_EX(1, 2);
@@ -2415,8 +2456,7 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC)
} else if (OP2_TYPE == IS_VAR &&
opline->extended_value == ZEND_RETURNS_FUNCTION &&
- UNEXPECTED(!(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) {
-
+ UNEXPECTED(!Z_ISREF_P(value_ptr))) {
zend_error(E_NOTICE, "Only variables should be assigned by reference");
if (UNEXPECTED(EG(exception) != NULL)) {
FREE_OP2_VAR_PTR();
@@ -2454,21 +2494,49 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
zend_execute_data *old_execute_data;
uint32_t call_info = EX_CALL_INFO();
- if (EXPECTED(ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION)) {
- zend_object *object;
+ if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED)) == 0)) {
+ i_free_compiled_variables(execute_data);
+
+ EG(current_execute_data) = EX(prev_execute_data);
+ if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+ zend_object *object = Z_OBJ(execute_data->This);
+#if 0
+ if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+#else
+ if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+#endif
+ GC_REFCOUNT(object)--;
+ if (GC_REFCOUNT(object) == 1) {
+ zend_object_store_ctor_failed(object);
+ }
+ }
+ OBJ_RELEASE(object);
+ } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
+ }
+ EG(vm_stack_top) = (zval*)execute_data;
+ execute_data = EX(prev_execute_data);
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ const zend_op *old_opline = EX(opline);
+ zend_throw_exception_internal(NULL);
+ if (RETURN_VALUE_USED(old_opline)) {
+ zval_ptr_dtor(EX_VAR(old_opline->result.var));
+ }
+ HANDLE_EXCEPTION_LEAVE();
+ }
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) {
i_free_compiled_variables(execute_data);
- if (UNEXPECTED(EX(symbol_table) != NULL)) {
+
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_clean_and_cache_symbol_table(EX(symbol_table));
}
- zend_vm_stack_free_extra_args_ex(call_info, execute_data);
- old_execute_data = execute_data;
- execute_data = EG(current_execute_data) = EX(prev_execute_data);
- if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
- OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
- }
+ EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- object = Z_OBJ(old_execute_data->This);
+ zend_object *object = Z_OBJ(execute_data->This);
#if 0
if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
#else
@@ -2480,15 +2548,19 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
}
}
OBJ_RELEASE(object);
+ } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
}
- EG(scope) = EX(func)->op_array.scope;
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+ old_execute_data = execute_data;
+ execute_data = EX(prev_execute_data);
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
if (UNEXPECTED(EG(exception) != NULL)) {
const zend_op *old_opline = EX(opline);
zend_throw_exception_internal(NULL);
- if (old_opline->opcode != ZEND_HANDLE_EXCEPTION && RETURN_VALUE_USED(old_opline)) {
+ if (RETURN_VALUE_USED(old_opline)) {
zval_ptr_dtor(EX_VAR(old_opline->result.var));
}
HANDLE_EXCEPTION_LEAVE();
@@ -2496,8 +2568,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
- }
- if (EXPECTED((ZEND_CALL_KIND_EX(call_info) & ZEND_CALL_TOP) == 0)) {
+ } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) {
zend_detach_symbol_table(execute_data);
destroy_op_array(&EX(func)->op_array);
efree_size(EX(func), sizeof(zend_op_array));
@@ -2514,23 +2585,26 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else {
- if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
+ if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) {
i_free_compiled_variables(execute_data);
- if (UNEXPECTED(EX(symbol_table) != NULL)) {
- zend_clean_and_cache_symbol_table(EX(symbol_table));
+ if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_clean_and_cache_symbol_table(EX(symbol_table));
+ }
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
}
- zend_vm_stack_free_extra_args_ex(call_info, execute_data);
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
}
+ ZEND_VM_RETURN();
} else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
zend_array *symbol_table = EX(symbol_table);
zend_detach_symbol_table(execute_data);
old_execute_data = EX(prev_execute_data);
while (old_execute_data) {
- if (old_execute_data->func && ZEND_USER_CODE(old_execute_data->func->op_array.type)) {
+ if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
if (old_execute_data->symbol_table == symbol_table) {
zend_attach_symbol_table(old_execute_data);
}
@@ -2539,9 +2613,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
old_execute_data = old_execute_data->prev_execute_data;
}
EG(current_execute_data) = EX(prev_execute_data);
+ ZEND_VM_RETURN();
}
-
- ZEND_VM_RETURN();
}
}
@@ -3033,7 +3106,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T
object = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(object) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_OP2();
HANDLE_EXCEPTION();
@@ -3093,6 +3166,9 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T
EXPECTED(obj == orig_obj)) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc);
}
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
}
call_info = ZEND_CALL_NESTED_FUNCTION;
@@ -3205,6 +3281,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc);
}
}
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
if (OP2_TYPE != IS_CONST) {
FREE_OP2();
}
@@ -3213,16 +3292,19 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
zend_throw_error(NULL, "Cannot call constructor");
HANDLE_EXCEPTION();
}
- if (Z_OBJ(EX(This)) && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
+ if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name));
HANDLE_EXCEPTION();
}
fbc = ce->constructor;
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
}
object = NULL;
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
- if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
+ if (Z_TYPE(EX(This)) == IS_OBJECT && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
ce = object->ce;
} else {
@@ -3251,7 +3333,11 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
/* previous opcode is ZEND_FETCH_CLASS */
if ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
- ce = EX(called_scope);
+ if (Z_TYPE(EX(This)) == IS_OBJECT) {
+ ce = Z_OBJCE(EX(This));
+ } else {
+ ce = Z_CE(EX(This));
+ }
}
}
@@ -3270,17 +3356,20 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM)
zval *function_name, *func;
zend_execute_data *call;
- fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
+ function_name = (zval*)EX_CONSTANT(opline->op2);
+ fbc = CACHED_PTR(Z_CACHE_SLOT_P(function_name));
if (UNEXPECTED(fbc == NULL)) {
- function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
- func = zend_hash_find(EG(function_table), Z_STR_P(function_name));
+ func = zend_hash_find(EG(function_table), Z_STR_P(function_name+1));
if (UNEXPECTED(func == NULL)) {
SAVE_OPLINE();
- zend_throw_error(NULL, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
+ zend_throw_error(NULL, "Call to undefined function %s()", Z_STRVAL_P(function_name));
HANDLE_EXCEPTION();
}
fbc = Z_FUNC_P(func);
- CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
+ CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc);
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL, NULL);
@@ -3293,195 +3382,21 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM)
ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV, NUM)
{
USE_OPLINE
- zend_function *fbc;
- zval *function_name, *func;
- zend_string *lcname;
zend_free_op free_op2;
- zend_class_entry *called_scope;
- zend_object *object;
+ zval *function_name;
zend_execute_data *call;
- uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
SAVE_OPLINE();
function_name = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
ZEND_VM_C_LABEL(try_function_name):
if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
- const char *colon;
-
- if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL &&
- colon > Z_STRVAL_P(function_name) &&
- *(colon-1) == ':'
- ) {
- zend_string *mname;
- size_t cname_length = colon - Z_STRVAL_P(function_name) - 1;
- size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1);
-
- lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0);
-
- object = NULL;
- 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_VM_NEXT_OPCODE_CHECK_EXCEPTION();
- }
-
- mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0);
-
- if (called_scope->get_static_method) {
- fbc = called_scope->get_static_method(called_scope, mname);
- } else {
- fbc = zend_std_get_static_method(called_scope, mname, NULL);
- }
- 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_string_release(lcname);
- zend_string_release(mname);
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
-
- zend_string_release(lcname);
- zend_string_release(mname);
-
- 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)) {
- HANDLE_EXCEPTION();
- }
- } 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));
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
- }
- } else {
- if (Z_STRVAL_P(function_name)[0] == '\\') {
- lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
- zend_str_tolower_copy(ZSTR_VAL(lcname), Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
- } else {
- lcname = zend_string_tolower(Z_STR_P(function_name));
- }
- if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
- zend_throw_error(NULL, "Call to undefined function %s()", Z_STRVAL_P(function_name));
- zend_string_release(lcname);
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
- zend_string_release(lcname);
-
- fbc = Z_FUNC_P(func);
- called_scope = NULL;
- object = NULL;
- }
- FREE_OP2();
- } else if (OP2_TYPE != IS_CONST &&
- EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
- Z_OBJ_HANDLER_P(function_name, get_closure) &&
- Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
- 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)++;
- call_info |= ZEND_CALL_CLOSURE;
- } else if (object) {
- call_info |= ZEND_CALL_RELEASE_THIS;
- GC_REFCOUNT(object)++; /* For $this pointer */
- }
- FREE_OP2();
- } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
- zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
- zval *obj;
- zval *method;
- obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0);
- method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1);
-
- if (!obj || !method) {
- zend_throw_error(NULL, "Array callback has to contain indices 0 and 1");
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
-
- ZVAL_DEREF(obj);
- if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) {
- zend_throw_error(NULL, "First array member is not a valid class name or object");
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
-
- ZVAL_DEREF(method);
- if (Z_TYPE_P(method) != IS_STRING) {
- zend_throw_error(NULL, "Second array member is not a valid method");
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
-
- if (Z_TYPE_P(obj) == IS_STRING) {
- object = NULL;
- called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
- if (UNEXPECTED(called_scope == NULL)) {
- ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
- }
-
- if (called_scope->get_static_method) {
- fbc = called_scope->get_static_method(called_scope, Z_STR_P(method));
- } else {
- fbc = zend_std_get_static_method(called_scope, 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(called_scope->name), Z_STRVAL_P(method));
- }
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
- 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)) {
- HANDLE_EXCEPTION();
- }
- } 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));
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
- }
- } else {
- called_scope = Z_OBJCE_P(obj);
- object = Z_OBJ_P(obj);
-
- 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));
- }
- FREE_OP2();
- HANDLE_EXCEPTION();
- }
-
- if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
- object = NULL;
- } else {
- call_info |= ZEND_CALL_RELEASE_THIS;
- GC_REFCOUNT(object)++; /* For $this pointer */
- }
- }
- FREE_OP2();
- } else if ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) {
+ call = zend_init_dynamic_call_string(Z_STR_P(function_name), opline->extended_value);
+ } else if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT)) {
+ call = zend_init_dynamic_call_object(function_name, opline->extended_value);
+ } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY)) {
+ call = zend_init_dynamic_call_array(Z_ARRVAL_P(function_name), opline->extended_value);
+ } else if ((OP2_TYPE & (IS_VAR|IS_CV)) && EXPECTED(Z_TYPE_P(function_name) == IS_REFERENCE)) {
function_name = Z_REFVAL_P(function_name);
ZEND_VM_C_GOTO(try_function_name);
} else {
@@ -3492,11 +3407,15 @@ ZEND_VM_C_LABEL(try_function_name):
}
}
zend_throw_error(NULL, "Function name must be a string");
- FREE_OP2();
+ call = NULL;
+ }
+
+ FREE_OP2();
+
+ if (UNEXPECTED(!call)) {
HANDLE_EXCEPTION();
}
- call = zend_vm_stack_push_call_frame(call_info,
- fbc, opline->extended_value, called_scope, object);
+
call->prev_execute_data = EX(call);
EX(call) = call;
@@ -3514,12 +3433,14 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
zend_class_entry *called_scope;
zend_object *object;
zend_execute_data *call;
- uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
+ uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
SAVE_OPLINE();
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
func = fcc.function_handler;
+ called_scope = fcc.called_scope;
+ object = fcc.object;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
/* Delay closure destruction until its invocation */
if (OP2_TYPE & (IS_VAR|IS_CV)) {
@@ -3528,10 +3449,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
GC_REFCOUNT((zend_object*)func->common.prototype)++;
call_info |= ZEND_CALL_CLOSURE;
- }
- called_scope = fcc.called_scope;
- object = fcc.object;
- if (object) {
+ } else if (object) {
call_info |= ZEND_CALL_RELEASE_THIS;
GC_REFCOUNT(object)++; /* For $this pointer */
}
@@ -3545,6 +3463,9 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
HANDLE_EXCEPTION();
}
}
+ if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) {
+ init_func_run_time_cache(&func->op_array);
+ }
} else {
zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error);
efree(error);
@@ -3585,6 +3506,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM)
}
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
@@ -3614,6 +3538,9 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM)
}
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc);
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
}
call = zend_vm_stack_push_call_frame_ex(
@@ -3641,7 +3568,6 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = 0;
fbc->internal_function.handler(call, ret);
@@ -3650,6 +3576,7 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
EG(exception) || !call->func ||
!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, ret));
+ ZEND_ASSERT(!Z_ISREF_P(ret));
#endif
EG(current_execute_data) = call->prev_execute_data;
@@ -3668,8 +3595,8 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
HANDLE_EXCEPTION();
}
- ZEND_VM_INTERRUPT_CHECK();
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_SET_OPCODE(opline + 1);
+ ZEND_VM_CONTINUE();
}
ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL))
@@ -3682,17 +3609,14 @@ ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL))
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
- EG(scope) = NULL;
ret = NULL;
- call->symbol_table = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = 0;
}
call->prev_execute_data = execute_data;
- i_init_func_execute_data(call, &fbc->op_array, ret, 0);
+ i_init_func_execute_data(call, &fbc->op_array, ret);
ZEND_VM_ENTER();
}
@@ -3708,32 +3632,16 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
EX(call) = call->prev_execute_data;
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
- EG(scope) = NULL;
- if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
- if (EXPECTED(RETURN_VALUE_USED(opline))) {
- ret = EX_VAR(opline->result.var);
- zend_generator_create_zval(call, &fbc->op_array, ret);
- Z_VAR_FLAGS_P(ret) = 0;
- } else {
- zend_vm_stack_free_args(call);
- }
-
- zend_vm_stack_free_call_frame(call);
- } else {
- ret = NULL;
- call->symbol_table = NULL;
- if (RETURN_VALUE_USED(opline)) {
- ret = EX_VAR(opline->result.var);
- ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = 0;
- }
+ ret = NULL;
+ if (RETURN_VALUE_USED(opline)) {
+ ret = EX_VAR(opline->result.var);
+ ZVAL_NULL(ret);
+ }
- call->prev_execute_data = execute_data;
- i_init_func_execute_data(call, &fbc->op_array, ret, 0);
+ call->prev_execute_data = execute_data;
+ i_init_func_execute_data(call, &fbc->op_array, ret);
- ZEND_VM_ENTER();
- }
- EG(scope) = EX(func)->op_array.scope;
+ ZEND_VM_ENTER();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
@@ -3751,34 +3659,25 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
- if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
- uint32_t i;
- uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
- zval *p = ZEND_CALL_ARG(call, 1);
-
- for (i = 0; i < num_args; ++i) {
- if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
- EG(current_execute_data) = call->prev_execute_data;
- zend_vm_stack_free_args(call);
- zend_vm_stack_free_call_frame(call);
- zend_throw_exception_internal(NULL);
- HANDLE_EXCEPTION();
- }
- p++;
- }
+ if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
+ && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
+ zend_vm_stack_free_call_frame(call);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
fbc->internal_function.handler(call, ret);
#if ZEND_DEBUG
- ZEND_ASSERT(
- EG(exception) || !call->func ||
- !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
- zend_verify_internal_return_type(call->func, ret));
+ if (!EG(exception) && call->func) {
+ ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
+ zend_verify_internal_return_type(call->func, ret));
+ ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ ? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
+ }
#endif
EG(current_execute_data) = call->prev_execute_data;
@@ -3797,8 +3696,8 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
}
HANDLE_EXCEPTION();
}
- ZEND_VM_INTERRUPT_CHECK();
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_SET_OPCODE(opline + 1);
+ ZEND_VM_CONTINUE();
}
ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
@@ -3830,74 +3729,37 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
LOAD_OPLINE();
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
- EG(scope) = fbc->common.scope;
- if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
- if (EXPECTED(RETURN_VALUE_USED(opline))) {
- ret = EX_VAR(opline->result.var);
- zend_generator_create_zval(call, &fbc->op_array, ret);
- Z_VAR_FLAGS_P(ret) = 0;
- } else {
- if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
- OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
- }
- zend_vm_stack_free_args(call);
- }
- } else {
- ret = NULL;
- call->symbol_table = NULL;
- if (RETURN_VALUE_USED(opline)) {
- ret = EX_VAR(opline->result.var);
- ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = 0;
- }
+ ret = NULL;
+ if (RETURN_VALUE_USED(opline)) {
+ ret = EX_VAR(opline->result.var);
+ ZVAL_NULL(ret);
+ }
- call->prev_execute_data = execute_data;
- i_init_func_execute_data(call, &fbc->op_array, ret, 1);
+ call->prev_execute_data = execute_data;
+ i_init_func_execute_data(call, &fbc->op_array, ret);
- if (EXPECTED(zend_execute_ex == execute_ex)) {
- ZEND_VM_ENTER();
- } else {
- ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
- zend_execute_ex(call);
- }
+ if (EXPECTED(zend_execute_ex == execute_ex)) {
+ ZEND_VM_ENTER();
+ } else {
+ ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
+ zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
- int should_change_scope = 0;
zval retval;
- if (fbc->common.scope) {
- should_change_scope = 1;
- EG(scope) = fbc->common.scope;
- }
-
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
- if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
- uint32_t i;
- uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
- zval *p = ZEND_CALL_ARG(call, 1);
-
- for (i = 0; i < num_args; ++i) {
- if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
- EG(current_execute_data) = call->prev_execute_data;
- zend_vm_stack_free_args(call);
- if (RETURN_VALUE_USED(opline)) {
- ZVAL_UNDEF(EX_VAR(opline->result.var));
- }
- if (UNEXPECTED(should_change_scope)) {
- ZEND_VM_C_GOTO(fcall_end_change_scope);
- } else {
- ZEND_VM_C_GOTO(fcall_end);
- }
- }
- p++;
+ if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
+ && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
+ if (RETURN_VALUE_USED(opline)) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
}
+ ZEND_VM_C_GOTO(fcall_end);
}
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
- Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */
@@ -3907,10 +3769,12 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
}
#if ZEND_DEBUG
- ZEND_ASSERT(
- EG(exception) || !call->func ||
- !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
- zend_verify_internal_return_type(call->func, ret));
+ if (!EG(exception) && call->func) {
+ ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
+ zend_verify_internal_return_type(call->func, ret));
+ ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ ? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
+ }
#endif
EG(current_execute_data) = call->prev_execute_data;
@@ -3920,52 +3784,23 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
zval_ptr_dtor(ret);
}
- if (UNEXPECTED(should_change_scope)) {
- ZEND_VM_C_GOTO(fcall_end_change_scope);
- } else {
- ZEND_VM_C_GOTO(fcall_end);
- }
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
- /* Not sure what should be done here if it's a static method */
- object = Z_OBJ(call->This);
- if (UNEXPECTED(object == NULL)) {
- zend_vm_stack_free_args(call);
- if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
- zend_string_release(fbc->common.function_name);
- }
- efree(fbc);
- zend_vm_stack_free_call_frame(call);
-
- zend_throw_error(NULL, "Cannot call overloaded function for non-object");
- HANDLE_EXCEPTION();
- }
-
- EG(scope) = fbc->common.scope;
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
- ZVAL_NULL(ret);
call->prev_execute_data = execute_data;
- EG(current_execute_data) = call;
- object->handlers->call_method(fbc->common.function_name, object, call, ret);
- EG(current_execute_data) = call->prev_execute_data;
- zend_vm_stack_free_args(call);
-
- if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
- zend_string_release(fbc->common.function_name);
+ if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {
+ HANDLE_EXCEPTION();
}
- efree(fbc);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(ret);
- } else {
- Z_VAR_FLAGS_P(ret) = 0;
}
}
-ZEND_VM_C_LABEL(fcall_end_change_scope):
+ZEND_VM_C_LABEL(fcall_end):
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
object = Z_OBJ(call->This);
#if 0
@@ -3980,9 +3815,7 @@ ZEND_VM_C_LABEL(fcall_end_change_scope):
}
OBJ_RELEASE(object);
}
- EG(scope) = EX(func)->op_array.scope;
-ZEND_VM_C_LABEL(fcall_end):
zend_vm_stack_free_call_frame(call);
if (UNEXPECTED(EG(exception) != NULL)) {
zend_throw_exception_internal(NULL);
@@ -3992,8 +3825,8 @@ ZEND_VM_C_LABEL(fcall_end):
HANDLE_EXCEPTION();
}
- ZEND_VM_INTERRUPT_CHECK();
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_SET_OPCODE(opline + 1);
+ ZEND_VM_CONTINUE();
}
ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
@@ -4055,46 +3888,61 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE
zval *retval_ptr;
+ zval *return_value;
zend_free_op free_op1;
retval_ptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ return_value = EX(return_value);
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) {
SAVE_OPLINE();
retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R);
- if (EX(return_value)) {
- ZVAL_NULL(EX(return_value));
+ if (return_value) {
+ ZVAL_NULL(return_value);
}
- } else if (!EX(return_value)) {
+ } else if (!return_value) {
if (OP1_TYPE & (IS_VAR|IS_TMP_VAR)) {
if (Z_REFCOUNTED_P(free_op1) && !Z_DELREF_P(free_op1)) {
SAVE_OPLINE();
- zval_dtor_func_for_ptr(Z_COUNTED_P(free_op1));
+ zval_dtor_func(Z_COUNTED_P(free_op1));
}
}
} else {
if ((OP1_TYPE & (IS_CONST|IS_TMP_VAR))) {
- ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(EX(return_value)))) {
- zval_copy_ctor_func(EX(return_value));
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(return_value))) {
+ Z_ADDREF_P(return_value);
}
}
} else if (OP1_TYPE == IS_CV) {
- ZVAL_DEREF(retval_ptr);
- ZVAL_COPY(EX(return_value), retval_ptr);
+ if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) {
+ ZVAL_NULL(retval_ptr);
+ } else {
+ Z_ADDREF_P(return_value);
+ }
+ } else {
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY(return_value, retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
} else /* if (OP1_TYPE == IS_VAR) */ {
if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
retval_ptr = Z_REFVAL_P(retval_ptr);
- ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
efree_size(ref, sizeof(zend_reference));
} else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
Z_ADDREF_P(retval_ptr);
}
} else {
- ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
}
}
}
@@ -4117,14 +3965,16 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC)
retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
if (!EX(return_value)) {
- if (OP1_TYPE == IS_TMP_VAR) {
- FREE_OP1();
- }
+ FREE_OP1();
} else {
- ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
- Z_VAR_FLAGS_P(EX(return_value)) = IS_VAR_RET_REF;
- if (OP1_TYPE != IS_TMP_VAR) {
- zval_opt_copy_ctor_no_imm(EX(return_value));
+ if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
+ break;
+ }
+
+ ZVAL_NEW_REF(EX(return_value), retval_ptr);
+ if (OP1_TYPE == IS_CONST) {
+ if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
}
}
break;
@@ -4134,13 +3984,12 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC)
if (OP1_TYPE == IS_VAR) {
if (retval_ptr == &EG(uninitialized_zval) ||
- (opline->extended_value == ZEND_RETURNS_FUNCTION &&
- !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) {
+ (opline->extended_value == ZEND_RETURNS_FUNCTION && !Z_ISREF_P(retval_ptr))) {
zend_error(E_NOTICE, "Only variable references should be returned by reference");
if (EX(return_value)) {
ZVAL_NEW_REF(EX(return_value), retval_ptr);
- Z_VAR_FLAGS_P(EX(return_value)) = IS_VAR_RET_REF;
- if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+ } else {
+ FREE_OP1_VAR_PTR();
}
break;
}
@@ -4150,14 +3999,82 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC)
ZVAL_MAKE_REF(retval_ptr);
Z_ADDREF_P(retval_ptr);
ZVAL_REF(EX(return_value), Z_REF_P(retval_ptr));
- Z_VAR_FLAGS_P(EX(return_value)) = IS_VAR_RET_REF;
}
+
+ FREE_OP1_VAR_PTR();
} while (0);
- FREE_OP1_VAR_PTR();
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
}
+ZEND_VM_HANDLER(41, ZEND_GENERATOR_CREATE, ANY, ANY)
+{
+ zval *return_value = EX(return_value);
+
+ if (EXPECTED(return_value)) {
+ USE_OPLINE
+ zend_generator *generator;
+ zend_execute_data *gen_execute_data;
+ uint32_t num_args, used_stack, call_info;
+
+ object_init_ex(return_value, zend_ce_generator);
+
+ /*
+ * Normally the execute_data is allocated on the VM stack (because it does
+ * not actually do any allocation and thus is faster). For generators
+ * though this behavior would be suboptimal, because the (rather large)
+ * structure would have to be copied back and forth every time execution is
+ * suspended or resumed. That's why for generators the execution context
+ * is allocated on heap.
+ */
+ num_args = EX_NUM_ARGS();
+ used_stack = (ZEND_CALL_FRAME_SLOT + num_args + EX(func)->op_array.last_var + EX(func)->op_array.T - MIN(EX(func)->op_array.num_args, num_args)) * sizeof(zval);
+ gen_execute_data = (zend_execute_data*)emalloc(used_stack);
+ memcpy(gen_execute_data, execute_data, used_stack);
+
+ /* Save execution context in generator object. */
+ generator = (zend_generator *) Z_OBJ_P(EX(return_value));
+ generator->execute_data = gen_execute_data;
+ generator->frozen_call_stack = NULL;
+ generator->execute_fake.opline = NULL;
+ generator->execute_fake.func = NULL;
+ generator->execute_fake.prev_execute_data = NULL;
+ ZVAL_OBJ(&generator->execute_fake.This, (zend_object *) generator);
+
+ gen_execute_data->opline = opline + 1;
+ /* EX(return_value) keeps pointer to zend_object (not a real zval) */
+ gen_execute_data->return_value = (zval*)generator;
+ call_info = Z_TYPE_INFO(EX(This));
+ if ((call_info & Z_TYPE_MASK) == IS_OBJECT
+ && !(call_info & ((ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS) << ZEND_CALL_INFO_SHIFT))) {
+ ZEND_ADD_CALL_FLAG_EX(call_info, ZEND_CALL_RELEASE_THIS);
+ Z_ADDREF(gen_execute_data->This);
+ }
+ ZEND_ADD_CALL_FLAG_EX(call_info, (ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | ZEND_CALL_GENERATOR));
+ Z_TYPE_INFO(gen_execute_data->This) = call_info;
+ gen_execute_data->prev_execute_data = NULL;
+
+ call_info = EX_CALL_INFO();
+ EG(current_execute_data) = EX(prev_execute_data);
+ if (EXPECTED(!(call_info & (ZEND_CALL_TOP|ZEND_CALL_ALLOCATED)))) {
+ EG(vm_stack_top) = (zval*)execute_data;
+ execute_data = EX(prev_execute_data);
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else if (EXPECTED(!(call_info & ZEND_CALL_TOP))) {
+ zend_execute_data *old_execute_data = execute_data;
+ execute_data = EX(prev_execute_data);
+ zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else {
+ ZEND_VM_RETURN();
+ }
+ } else {
+ ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+ }
+}
+
ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE
@@ -4173,8 +4090,8 @@ ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY)
if ((OP1_TYPE & (IS_CONST|IS_TMP_VAR))) {
ZVAL_COPY_VALUE(&generator->retval, retval);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
- zval_copy_ctor_func(&generator->retval);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED(generator->retval))) {
+ Z_ADDREF(generator->retval);
}
}
} else if (OP1_TYPE == IS_CV) {
@@ -4293,7 +4210,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
}
}
-ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, NUM)
+ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMPVAR, NUM)
{
USE_OPLINE
zval *value, *arg;
@@ -4303,8 +4220,8 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, NUM)
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY_VALUE(arg, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) {
- zval_copy_ctor_func(arg);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(arg))) {
+ Z_ADDREF_P(arg);
}
}
ZEND_VM_NEXT_OPCODE();
@@ -4334,8 +4251,8 @@ ZEND_VM_C_LABEL(send_val_by_ref):
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY_VALUE(arg, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) {
- zval_copy_ctor_func(arg);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(arg))) {
+ Z_ADDREF_P(arg);
}
}
ZEND_VM_NEXT_OPCODE();
@@ -4380,41 +4297,63 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM)
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM, SEND)
+ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM)
{
USE_OPLINE
zend_free_op free_op1;
zval *varptr, *arg;
- if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND)) {
- if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
- ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR);
- }
+ varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ arg = ZEND_CALL_VAR(EX(call), opline->result.var);
+ ZVAL_COPY_VALUE(arg, varptr);
+
+ if (EXPECTED(Z_ISREF_P(varptr))) {
+ ZEND_VM_NEXT_OPCODE();
}
- varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ SAVE_OPLINE();
+ zend_error(E_NOTICE, "Only variables should be passed by reference");
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
- if ((!(opline->extended_value & ZEND_ARG_SEND_FUNCTION) ||
- (Z_VAR_FLAGS_P(varptr) & IS_VAR_RET_REF)) &&
- (Z_ISREF_P(varptr) || Z_TYPE_P(varptr) == IS_OBJECT)) {
+ZEND_VM_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, NUM, SPEC(QUICK_ARG))
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *varptr, *arg;
+ uint32_t arg_num = opline->op2.num;
- ZVAL_MAKE_REF(varptr);
+ if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
+ if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR);
+ }
+
+ varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ arg = ZEND_CALL_VAR(EX(call), opline->result.var);
+ ZVAL_COPY_VALUE(arg, varptr);
+
+ if (EXPECTED(Z_ISREF_P(varptr) ||
+ QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
+ ZEND_VM_NEXT_OPCODE();
+ }
} else {
- if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ?
- !(opline->extended_value & ZEND_ARG_SEND_SILENT) :
- !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
- SAVE_OPLINE();
- zend_error(E_NOTICE, "Only variables should be passed by reference");
- arg = ZEND_CALL_VAR(EX(call), opline->result.var);
- ZVAL_COPY_VALUE(arg, varptr);
- ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+ if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR);
}
- }
- arg = ZEND_CALL_VAR(EX(call), opline->result.var);
- ZVAL_COPY_VALUE(arg, varptr);
+ varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ arg = ZEND_CALL_VAR(EX(call), opline->result.var);
+ ZVAL_COPY_VALUE(arg, varptr);
- ZEND_VM_NEXT_OPCODE();
+ if (EXPECTED(Z_ISREF_P(varptr) ||
+ ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
+ ZEND_VM_NEXT_OPCODE();
+ }
+ }
+
+ SAVE_OPLINE();
+ zend_error(E_NOTICE, "Only variables should be passed by reference");
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, NUM)
@@ -4428,7 +4367,8 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, NUM)
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(varptr))) {
- ZVAL_NEW_REF(arg, &EG(uninitialized_zval));
+ ZVAL_NEW_EMPTY_REF(arg);
+ ZVAL_NULL(Z_REFVAL_P(arg));
ZEND_VM_NEXT_OPCODE();
}
@@ -4513,7 +4453,7 @@ ZEND_VM_C_LABEL(send_again):
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht));
- if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
+ if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) {
uint32_t i;
int separate = 0;
@@ -4525,7 +4465,7 @@ ZEND_VM_C_LABEL(send_again):
}
}
if (separate) {
- zval_copy_ctor(args);
+ SEPARATE_ARRAY(args);
ht = Z_ARRVAL_P(args);
}
}
@@ -4539,7 +4479,7 @@ ZEND_VM_C_LABEL(send_again):
top = ZEND_CALL_ARG(EX(call), arg_num);
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
- if (!Z_IMMUTABLE_P(args)) {
+ if (Z_REFCOUNT_P(args) == 1) {
ZVAL_MAKE_REF(arg);
Z_ADDREF_P(arg);
ZVAL_REF(top, Z_REF_P(arg));
@@ -4577,35 +4517,32 @@ ZEND_VM_C_LABEL(send_again):
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
- if (UNEXPECTED(EG(exception) != NULL)) {
- ZEND_VM_C_GOTO(unpack_iter_dtor);
- }
}
for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) {
zval *arg, *top;
if (UNEXPECTED(EG(exception) != NULL)) {
- ZEND_VM_C_GOTO(unpack_iter_dtor);
+ break;
}
arg = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- ZEND_VM_C_GOTO(unpack_iter_dtor);
+ break;
}
if (iter->funcs->get_current_key) {
zval key;
iter->funcs->get_current_key(iter, &key);
if (UNEXPECTED(EG(exception) != NULL)) {
- ZEND_VM_C_GOTO(unpack_iter_dtor);
+ break;
}
if (Z_TYPE(key) == IS_STRING) {
zend_throw_error(NULL,
"Cannot unpack Traversable with string keys");
zend_string_release(Z_STR(key));
- ZEND_VM_C_GOTO(unpack_iter_dtor);
+ break;
}
zval_dtor(&key);
@@ -4633,12 +4570,8 @@ ZEND_VM_C_LABEL(send_again):
ZEND_CALL_NUM_ARGS(EX(call))++;
iter->funcs->move_forward(iter);
- if (UNEXPECTED(EG(exception) != NULL)) {
- ZEND_VM_C_GOTO(unpack_iter_dtor);
- }
}
-ZEND_VM_C_LABEL(unpack_iter_dtor):
zend_iterator_dtor(iter);
}
} else if (EXPECTED(Z_ISREF_P(args))) {
@@ -4660,7 +4593,6 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
USE_OPLINE
zend_free_op free_op1;
zval *args;
- SAVE_OPLINE();
SAVE_OPLINE();
args = GET_OP1_ZVAL_PTR(BP_VAR_R);
@@ -4676,12 +4608,12 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
}
- if (Z_OBJ(EX(call)->This)) {
+ if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
OBJ_RELEASE(Z_OBJ(EX(call)->This));
}
EX(call)->func = (zend_function*)&zend_pass_function;
- EX(call)->called_scope = NULL;
Z_OBJ(EX(call)->This) = NULL;
+ ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
} else {
uint32_t arg_num;
HashTable *ht;
@@ -4691,22 +4623,6 @@ ZEND_VM_C_LABEL(send_array):
ht = Z_ARRVAL_P(args);
zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht));
- if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
- int separate = 0;
-
- /* check if any of arguments are going to be passed by reference */
- for (arg_num = 0; arg_num < zend_hash_num_elements(ht); arg_num++) {
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + 1)) {
- separate = 1;
- break;
- }
- }
- if (separate) {
- zval_copy_ctor(args);
- ht = Z_ARRVAL_P(args);
- }
- }
-
arg_num = 1;
param = ZEND_CALL_ARG(EX(call), 1);
ZEND_HASH_FOREACH_VAL(ht, arg) {
@@ -4723,30 +4639,23 @@ ZEND_VM_C_LABEL(send_array):
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
}
- if (Z_OBJ(EX(call)->This)) {
+ if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
OBJ_RELEASE(Z_OBJ(EX(call)->This));
}
EX(call)->func = (zend_function*)&zend_pass_function;
- EX(call)->called_scope = NULL;
Z_OBJ(EX(call)->This) = NULL;
-
+ ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
break;
}
-
- ZVAL_NEW_REF(arg, arg);
}
- Z_ADDREF_P(arg);
- } else{
+ } else {
if (Z_ISREF_P(arg) &&
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
/* don't separate references for __call */
arg = Z_REFVAL_P(arg);
}
- if (Z_OPT_REFCOUNTED_P(arg)) {
- Z_ADDREF_P(arg);
- }
}
- ZVAL_COPY_VALUE(param, arg);
+ ZVAL_COPY(param, arg);
ZEND_CALL_NUM_ARGS(EX(call))++;
arg_num++;
param++;
@@ -4768,7 +4677,6 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM)
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
if (UNEXPECTED(!Z_ISREF_P(arg))) {
-
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
@@ -4780,32 +4688,26 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM)
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
}
- if (Z_OBJ(EX(call)->This)) {
+ if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
OBJ_RELEASE(Z_OBJ(EX(call)->This));
}
ZVAL_UNDEF(param);
EX(call)->func = (zend_function*)&zend_pass_function;
- EX(call)->called_scope = NULL;
Z_OBJ(EX(call)->This) = NULL;
+ ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-
- ZVAL_NEW_REF(arg, arg);
}
- Z_ADDREF_P(arg);
} else {
if (Z_ISREF_P(arg) &&
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
/* don't separate references for __call */
arg = Z_REFVAL_P(arg);
}
- if (Z_OPT_REFCOUNTED_P(arg)) {
- Z_ADDREF_P(arg);
- }
}
- ZVAL_COPY_VALUE(param, arg);
+ ZVAL_COPY(param, arg);
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -4818,13 +4720,13 @@ ZEND_VM_HANDLER(63, ZEND_RECV, NUM, ANY)
if (UNEXPECTED(arg_num > EX_NUM_ARGS())) {
SAVE_OPLINE();
- zend_verify_missing_arg(execute_data, arg_num, CACHE_ADDR(opline->op2.num));
- ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+ zend_missing_arg_error(execute_data);
+ HANDLE_EXCEPTION();
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
SAVE_OPLINE();
- if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) {
+ if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
HANDLE_EXCEPTION();
}
}
@@ -4843,18 +4745,13 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, NUM, CONST)
arg_num = opline->op1.num;
param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
if (arg_num > EX_NUM_ARGS()) {
- ZVAL_COPY_VALUE(param, EX_CONSTANT(opline->op2));
+ ZVAL_COPY(param, EX_CONSTANT(opline->op2));
if (Z_OPT_CONSTANT_P(param)) {
SAVE_OPLINE();
- if (UNEXPECTED(zval_update_constant_ex(param, 0, NULL) != SUCCESS)) {
+ if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
ZVAL_UNDEF(param);
HANDLE_EXCEPTION();
}
- } else {
- /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
- if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) {
- zval_copy_ctor_func(param);
- }
}
}
@@ -4862,7 +4759,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, NUM, CONST)
zval *default_value = EX_CONSTANT(opline->op2);
SAVE_OPLINE();
- if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))))) {
+ if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))) || EG(exception))) {
HANDLE_EXCEPTION();
}
}
@@ -4991,6 +4888,14 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
SAVE_OPLINE();
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
+ } else if ((OP1_TYPE & IS_VAR) && UNEXPECTED(Z_ISREF_P(op1))) {
+ /* Don't keep lock on reference, lock the value instead */
+ if (UNEXPECTED(Z_REFCOUNT_P(op1) == 1)) {
+ ZVAL_UNREF(op1);
+ } else {
+ Z_DELREF_P(op1);
+ ZVAL_COPY(op1, Z_REFVAL_P(op1));
+ }
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op2) == IS_UNDEF)) {
op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
@@ -5002,12 +4907,13 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, JMP_ADDR, NUM)
+ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, ANY, NUM)
{
USE_OPLINE
zval *result;
zend_function *constructor;
zend_class_entry *ce;
+ zend_execute_data *call;
SAVE_OPLINE();
if (OP1_TYPE == IS_CONST) {
@@ -5036,21 +4942,33 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, JMP_ADDR, NUM)
constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
if (constructor == NULL) {
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next
+ * opcode is DO_FCALL in case EXT instructions are used. */
+ if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) {
+ ZEND_VM_NEXT_OPCODE_EX(1, 2);
+ }
+
+ /* Perform a dummy function call */
+ call = zend_vm_stack_push_call_frame(
+ ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function,
+ opline->extended_value, NULL, NULL);
} else {
+ if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) {
+ init_func_run_time_cache(&constructor->op_array);
+ }
/* We are not handling overloaded classes right now */
- zend_execute_data *call = zend_vm_stack_push_call_frame(
+ call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
constructor,
opline->extended_value,
ce,
Z_OBJ_P(result));
- call->prev_execute_data = EX(call);
- EX(call) = call;
Z_ADDREF_P(result);
-
- ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
+
+ call->prev_execute_data = EX(call);
+ EX(call) = call;
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
@@ -5058,14 +4976,14 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
USE_OPLINE
zend_free_op free_op1;
zval *obj;
- zend_class_entry *ce;
+ zend_class_entry *ce, *scope;
zend_function *clone;
zend_object_clone_obj_t clone_call;
SAVE_OPLINE();
obj = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(obj) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
HANDLE_EXCEPTION();
}
@@ -5104,16 +5022,18 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
if (clone->op_array.fn_flags & ZEND_ACC_PRIVATE) {
/* Ensure that if we're calling a private function, we're allowed to do so.
*/
- if (UNEXPECTED(ce != EG(scope))) {
- zend_throw_error(NULL, "Call to private %s::__clone() from context '%s'", ZSTR_VAL(ce->name), EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
+ scope = EX(func)->op_array.scope;
+ if (UNEXPECTED(ce != scope)) {
+ zend_throw_error(NULL, "Call to private %s::__clone() from context '%s'", ZSTR_VAL(ce->name), scope ? ZSTR_VAL(scope->name) : "");
FREE_OP1();
HANDLE_EXCEPTION();
}
} else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
/* Ensure that if we're calling a protected function, we're allowed to do so.
*/
- if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
- zend_throw_error(NULL, "Call to protected %s::__clone() from context '%s'", ZSTR_VAL(ce->name), EG(scope) ? ZSTR_VAL(EG(scope)->name) : "");
+ scope = EX(func)->op_array.scope;
+ if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
+ zend_throw_error(NULL, "Call to protected %s::__clone() from context '%s'", ZSTR_VAL(ce->name), scope ? ZSTR_VAL(scope->name) : "");
FREE_OP1();
HANDLE_EXCEPTION();
}
@@ -5175,7 +5095,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED, CONST, CONST_FETCH)
ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CONST)
{
- zend_class_entry *ce;
+ zend_class_entry *ce, *scope;
zend_class_constant *c;
zval *value;
USE_OPLINE
@@ -5218,15 +5138,14 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
}
if (EXPECTED((c = zend_hash_find_ptr(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
- if (!zend_verify_const_access(c, EG(scope))) {
+ scope = EX(func)->op_array.scope;
+ if (!zend_verify_const_access(c, scope)) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(ce->name), Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
value = &c->value;
if (Z_CONSTANT_P(value)) {
- EG(scope) = ce;
- zval_update_constant_ex(value, 1, NULL);
- EG(scope) = EX(func)->op_array.scope;
+ zval_update_constant_ex(value, ce);
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
@@ -5273,10 +5192,8 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSE
if (OP1_TYPE == IS_TMP_VAR) {
/* pass */
} else if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(expr_ptr))) {
- ZVAL_COPY_VALUE(&new_expr, expr_ptr);
- zval_copy_ctor_func(&new_expr);
- expr_ptr = &new_expr;
+ if (Z_REFCOUNTED_P(expr_ptr)) {
+ Z_ADDREF_P(expr_ptr);
}
} else if (OP1_TYPE == IS_CV) {
ZVAL_DEREF(expr_ptr);
@@ -5428,11 +5345,9 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
if (Z_TYPE_P(expr) == opline->extended_value) {
ZVAL_COPY_VALUE(result, expr);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(result))) {
- zval_copy_ctor_func(result);
- }
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(result))) Z_ADDREF_P(result);
} else if (OP1_TYPE != IS_TMP_VAR) {
- if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr);
+ if (Z_OPT_REFCOUNTED_P(result)) Z_ADDREF_P(result);
}
FREE_OP1_IF_VAR();
@@ -5446,9 +5361,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
if (Z_TYPE_P(expr) != IS_NULL) {
expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(expr))) {
- zval_copy_ctor_func(expr);
- }
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
} else {
if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr);
}
@@ -5462,11 +5375,9 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
if (Z_TYPE_P(expr) != IS_ARRAY) {
object_init(result);
if (Z_TYPE_P(expr) != IS_NULL) {
- expr = zend_hash_str_add_new(Z_OBJPROP_P(result), "scalar", sizeof("scalar")-1, expr);
+ expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(expr))) {
- zval_copy_ctor_func(expr);
- }
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
} else {
if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr);
}
@@ -5485,89 +5396,20 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL)
{
USE_OPLINE
- zend_op_array *new_op_array=NULL;
+ zend_op_array *new_op_array;
zend_free_op free_op1;
zval *inc_filename;
- zval tmp_inc_filename;
- zend_bool failure_retval=0;
SAVE_OPLINE();
- inc_filename = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
-
- ZVAL_UNDEF(&tmp_inc_filename);
- if (Z_TYPE_P(inc_filename) != IS_STRING) {
- if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) {
- inc_filename = GET_OP1_UNDEF_CV(inc_filename, BP_VAR_R);
- }
- ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename));
- inc_filename = &tmp_inc_filename;
- }
-
- if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) {
- if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == 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 (opline->extended_value) {
- 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) {
- failure_retval = zend_hash_exists(&EG(included_files), resolved_path);
- } else {
- resolved_path = zend_string_copy(Z_STR_P(inc_filename));
- }
-
- if (failure_retval) {
- /* do nothing, file already included */
- } else 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 (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) {
- new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE));
- zend_destroy_file_handle(&file_handle);
- } else {
- zend_file_handle_dtor(&file_handle);
- failure_retval=1;
- }
- } else {
- if (opline->extended_value == 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_string_release(resolved_path);
- }
- break;
- case ZEND_INCLUDE:
- case ZEND_REQUIRE:
- new_op_array = compile_filename(opline->extended_value, 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));
- }
+ inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ new_op_array = zend_include_or_eval(inc_filename, opline->extended_value);
FREE_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
+ } else if (new_op_array == ZEND_FAKE_OP_ARRAY) {
+ if (RETURN_VALUE_USED(opline)) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
} else if (EXPECTED(new_op_array != NULL)) {
zval *return_value = NULL;
zend_execute_data *call;
@@ -5576,19 +5418,21 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL)
return_value = EX_VAR(opline->result.var);
}
- new_op_array->scope = EG(scope);
+ new_op_array->scope = EX(func)->op_array.scope;
- call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE,
- (zend_function*)new_op_array, 0, EX(called_scope), Z_OBJ(EX(This)));
+ call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE,
+ (zend_function*)new_op_array, 0,
+ Z_TYPE(EX(This)) != IS_OBJECT ? Z_CE(EX(This)) : NULL,
+ Z_TYPE(EX(This)) == IS_OBJECT ? Z_OBJ(EX(This)) : NULL);
- if (EX(symbol_table)) {
+ if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
call->symbol_table = EX(symbol_table);
} else {
call->symbol_table = zend_rebuild_symbol_table();
}
call->prev_execute_data = execute_data;
- i_init_code_execute_data(call, new_op_array, return_value);
+ i_init_code_execute_data(call, new_op_array, return_value);
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
@@ -5603,12 +5447,11 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL)
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
-
} else if (RETURN_VALUE_USED(opline)) {
- ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval);
+ ZVAL_FALSE(EX_VAR(opline->result.var));
}
- ZEND_VM_INTERRUPT_CHECK();
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_SET_OPCODE(opline + 1);
+ ZEND_VM_CONTINUE();
}
ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ISSET)
@@ -5628,7 +5471,7 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ISSET)
if (!--GC_REFCOUNT(garbage)) {
ZVAL_UNDEF(var);
- zval_dtor_func_for_ptr(garbage);
+ zval_dtor_func(garbage);
} else {
zval *z = var;
ZVAL_DEREF(z);
@@ -5724,7 +5567,7 @@ ZEND_VM_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
+ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
@@ -5734,16 +5577,11 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
zend_string *key;
SAVE_OPLINE();
- container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
- zend_throw_error(NULL, "Using $this when not in object context");
- FREE_UNFETCHED_OP2();
- HANDLE_EXCEPTION();
- }
+ container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
do {
- if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
HashTable *ht;
ZEND_VM_C_LABEL(unset_dim_array):
@@ -5793,16 +5631,19 @@ ZEND_VM_C_LABEL(num_index_dim):
zend_error(E_WARNING, "Illegal offset type in unset");
}
break;
- } else if (OP1_TYPE != IS_UNUSED && Z_ISREF_P(container)) {
+ } else if (Z_ISREF_P(container)) {
container = Z_REFVAL_P(container);
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
ZEND_VM_C_GOTO(unset_dim_array);
}
}
+ if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+ container = GET_OP1_UNDEF_CV(container, BP_VAR_R);
+ }
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
offset = GET_OP2_UNDEF_CV(offset, BP_VAR_R);
}
- if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (UNEXPECTED(Z_OBJ_HT_P(container)->unset_dimension == NULL)) {
zend_throw_error(NULL, "Cannot use object as array");
} else {
@@ -5827,7 +5668,7 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -5887,6 +5728,13 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR)
if (OP1_TYPE != IS_TMP_VAR) {
Z_ADDREF_P(array_ptr);
}
+ if (Z_OBJ_P(array_ptr)->properties
+ && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+ if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+ GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+ }
+ Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+ }
fe_ht = Z_OBJPROP_P(array_ptr);
pos = 0;
p = fe_ht->arData;
@@ -6033,6 +5881,13 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR)
array_ptr = EX_VAR(opline->result.var);
ZVAL_COPY_VALUE(array_ptr, array_ref);
}
+ if (Z_OBJ_P(array_ptr)->properties
+ && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+ if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+ GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+ }
+ Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+ }
fe_ht = Z_OBJPROP_P(array_ptr);
p = fe_ht->arData;
while (1) {
@@ -6639,7 +6494,7 @@ ZEND_VM_C_LABEL(is_static_prop_return):
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, ISSET)
+ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|CV, CONST|TMPVAR|CV, ISSET)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
@@ -6649,17 +6504,10 @@ ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|THIS|CV, CO
zval *offset;
SAVE_OPLINE();
- container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS);
-
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
- zend_throw_error(NULL, "Using $this when not in object context");
- FREE_UNFETCHED_OP2();
- HANDLE_EXCEPTION();
- }
-
+ container = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_IS);
offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
- if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
HashTable *ht;
zval *value;
zend_string *str;
@@ -6726,8 +6574,7 @@ ZEND_VM_C_LABEL(num_index_prop):
offset = GET_OP2_UNDEF_CV(offset, BP_VAR_R);
}
- if (OP1_TYPE == IS_UNUSED ||
- (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(container) == IS_OBJECT))) {
+ if ((OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(container) == IS_OBJECT))) {
if (EXPECTED(Z_OBJ_HT_P(container)->has_dimension)) {
result =
((opline->extended_value & ZEND_ISSET) == 0) ^
@@ -6742,6 +6589,9 @@ ZEND_VM_C_LABEL(num_index_prop):
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
ZEND_VM_C_LABEL(isset_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)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
@@ -6787,7 +6637,7 @@ ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMPVAR|UNUSED|THIS|CV, C
SAVE_OPLINE();
container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS);
- if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_OBJ_P(container) == NULL)) {
+ if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
zend_throw_error(NULL, "Using $this when not in object context");
FREE_UNFETCHED_OP2();
HANDLE_EXCEPTION();
@@ -6862,7 +6712,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY)
do {
EG(error_reporting) = 0;
if (!EG(error_reporting_ini_entry)) {
- zend_ini_entry *p = zend_hash_str_find_ptr(EG(ini_directives), "error_reporting", sizeof("error_reporting")-1);
+ zend_ini_entry *p = zend_hash_find_ptr(EG(ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING]);
if (p) {
EG(error_reporting_ini_entry) = p;
} else {
@@ -6874,7 +6724,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY)
ALLOC_HASHTABLE(EG(modified_ini_directives));
zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
}
- if (EXPECTED(zend_hash_str_add_ptr(EG(modified_ini_directives), "error_reporting", sizeof("error_reporting")-1, EG(error_reporting_ini_entry)) != NULL)) {
+ if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING], EG(error_reporting_ini_entry)) != NULL)) {
EG(error_reporting_ini_entry)->orig_value = EG(error_reporting_ini_entry)->value;
EG(error_reporting_ini_entry)->orig_modifiable = EG(error_reporting_ini_entry)->modifiable;
EG(error_reporting_ini_entry)->modified = 1;
@@ -6912,19 +6762,20 @@ ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, JMP_ADDR)
value = Z_REFVAL_P(value);
}
if (i_zend_is_true(value)) {
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
+ zval *result = EX_VAR(opline->result.var);
+
+ ZVAL_COPY_VALUE(result, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- zval_copy_ctor_func(EX_VAR(opline->result.var));
- }
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(result))) Z_ADDREF_P(result);
} else if (OP1_TYPE == IS_CV) {
- if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
+ if (Z_OPT_REFCOUNTED_P(result)) Z_ADDREF_P(result);
} else if (OP1_TYPE == IS_VAR && ref) {
zend_reference *r = Z_REF_P(ref);
- if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
if (UNEXPECTED(--GC_REFCOUNT(r) == 0)) {
efree_size(r, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(result)) {
+ Z_ADDREF_P(result);
}
}
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
@@ -6952,19 +6803,19 @@ ZEND_VM_HANDLER(169, ZEND_COALESCE, CONST|TMP|VAR|CV, JMP_ADDR)
}
if (Z_TYPE_P(value) > IS_NULL) {
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
+ zval *result = EX_VAR(opline->result.var);
+ ZVAL_COPY_VALUE(result, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- zval_copy_ctor_func(EX_VAR(opline->result.var));
- }
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(result))) Z_ADDREF_P(result);
} else if (OP1_TYPE == IS_CV) {
- if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
+ if (Z_OPT_REFCOUNTED_P(result)) Z_ADDREF_P(result);
} else if (OP1_TYPE == IS_VAR && ref) {
zend_reference *r = Z_REF_P(ref);
- if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
if (UNEXPECTED(--GC_REFCOUNT(r) == 0)) {
efree_size(r, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(result)) {
+ Z_ADDREF_P(result);
}
}
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
@@ -6979,30 +6830,36 @@ ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY)
USE_OPLINE
zend_free_op free_op1;
zval *value;
+ zval *result = EX_VAR(opline->result.var);
value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
SAVE_OPLINE();
GET_OP1_UNDEF_CV(value, BP_VAR_R);
- ZVAL_NULL(EX_VAR(opline->result.var));
+ ZVAL_NULL(result);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
- if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) && Z_ISREF_P(value)) {
- ZVAL_COPY(EX_VAR(opline->result.var), Z_REFVAL_P(value));
- if (OP1_TYPE == IS_VAR) {
+ if (OP1_TYPE == IS_CV) {
+ ZVAL_DEREF(value);
+ ZVAL_COPY(result, value);
+ } else if (OP1_TYPE == IS_VAR) {
+ if (UNEXPECTED(Z_ISREF_P(value))) {
+ ZVAL_COPY_VALUE(result, Z_REFVAL_P(value));
if (UNEXPECTED(Z_DELREF_P(value) == 0)) {
efree_size(Z_REF_P(value), sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(result)) {
+ Z_ADDREF_P(result);
}
+ } else {
+ ZVAL_COPY_VALUE(result, value);
}
} else {
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
+ ZVAL_COPY_VALUE(result, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- zval_copy_ctor_func(EX_VAR(opline->result.var));
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(result))) {
+ Z_ADDREF_P(result);
}
- } else if (OP1_TYPE == IS_CV) {
- if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value);
}
}
ZEND_VM_NEXT_OPCODE();
@@ -7014,7 +6871,7 @@ ZEND_VM_HANDLER(101, ZEND_EXT_STMT, ANY, ANY)
if (!EG(no_extensions)) {
SAVE_OPLINE();
- zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(func));
+ zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, execute_data);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE();
@@ -7026,7 +6883,7 @@ ZEND_VM_HANDLER(102, ZEND_EXT_FCALL_BEGIN, ANY, ANY)
if (!EG(no_extensions)) {
SAVE_OPLINE();
- zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(func));
+ zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, execute_data);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE();
@@ -7038,7 +6895,7 @@ ZEND_VM_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY)
if (!EG(no_extensions)) {
SAVE_OPLINE();
- zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(func));
+ zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, execute_data);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE();
@@ -7267,14 +7124,72 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
+ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_catch_offset, uint32_t op_num)
{
- uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
- int i;
- uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
- int in_finally = 0;
+ /* May be NULL during generator closing (only finally blocks are executed) */
+ zend_object *ex = EG(exception);
+
+ /* Walk try/catch/finally structures upwards, performing the necessary actions */
+ while (try_catch_offset != (uint32_t) -1) {
+ zend_try_catch_element *try_catch =
+ &EX(func)->op_array.try_catch_array[try_catch_offset];
+
+ if (op_num < try_catch->catch_op && ex) {
+ /* Go to catch block */
+ cleanup_live_vars(execute_data, op_num, try_catch->catch_op);
+ ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
+ ZEND_VM_CONTINUE();
+
+ } else if (op_num < try_catch->finally_op) {
+ /* Go to finally block */
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+ cleanup_live_vars(execute_data, op_num, try_catch->finally_op);
+ Z_OBJ_P(fast_call) = EG(exception);
+ EG(exception) = NULL;
+ fast_call->u2.lineno = (uint32_t)-1;
+ ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->finally_op]);
+ ZEND_VM_CONTINUE();
+
+ } else if (op_num < try_catch->finally_end) {
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+
+ /* cleanup incomplete RETURN statement */
+ if (fast_call->u2.lineno != (uint32_t)-1
+ && (EX(func)->op_array.opcodes[fast_call->u2.lineno].op2_type & (IS_TMP_VAR | IS_VAR))) {
+ zval *return_value = EX_VAR(EX(func)->op_array.opcodes[fast_call->u2.lineno].op2.var);
+
+ zval_ptr_dtor(return_value);
+ }
+
+ /* Chain potential exception from wrapping finally block */
+ if (Z_OBJ_P(fast_call)) {
+ if (ex) {
+ zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+ } else {
+ EG(exception) = Z_OBJ_P(fast_call);
+ }
+ ex = Z_OBJ_P(fast_call);
+ }
+ }
- ZEND_VM_INTERRUPT_CHECK();
+ try_catch_offset--;
+ }
+
+ /* Uncaught exception */
+ cleanup_live_vars(execute_data, op_num, 0);
+ if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
+ zend_generator *generator = zend_get_running_generator(execute_data);
+ zend_generator_close(generator, 1);
+ ZEND_VM_RETURN();
+ } else {
+ ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+ }
+}
+
+ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
+{
+ uint32_t throw_op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
+ uint32_t i, current_try_catch_offset = (uint32_t) -1;
{
const zend_op *exc_opline = EG(opline_before_exception);
@@ -7282,68 +7197,27 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
&& exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
/* exceptions thrown because of loop var destruction on return/break/...
* are logically thrown at the end of the foreach loop, so adjust the
- * op_num.
+ * throw_op_num.
*/
- op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
+ throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
}
}
+ /* Find the innermost try/catch/finally the exception was thrown in */
for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
- if (EX(func)->op_array.try_catch_array[i].try_op > op_num) {
+ zend_try_catch_element *try_catch = &EX(func)->op_array.try_catch_array[i];
+ if (try_catch->try_op > throw_op_num) {
/* further blocks will not be relevant... */
break;
}
- in_finally = 0;
- if (op_num < EX(func)->op_array.try_catch_array[i].catch_op) {
- catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op;
- }
- if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) {
- finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op;
- finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
- }
- if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op &&
- op_num < EX(func)->op_array.try_catch_array[i].finally_end) {
- finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
- in_finally = 1;
+ if (throw_op_num < try_catch->catch_op || throw_op_num < try_catch->finally_end) {
+ current_try_catch_offset = i;
}
}
- cleanup_unfinished_calls(execute_data, op_num);
-
- if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
- zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+ cleanup_unfinished_calls(execute_data, throw_op_num);
- cleanup_live_vars(execute_data, op_num, finally_op_num);
- if (in_finally && Z_OBJ_P(fast_call)) {
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
- }
- Z_OBJ_P(fast_call) = EG(exception);
- EG(exception) = NULL;
- fast_call->u2.lineno = (uint32_t)-1;
- ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
- ZEND_VM_CONTINUE();
- } else {
- cleanup_live_vars(execute_data, op_num, catch_op_num);
- if (in_finally) {
- /* we are going out of current finally scope */
- zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
-
- if (Z_OBJ_P(fast_call)) {
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
- Z_OBJ_P(fast_call) = NULL;
- }
- }
- if (catch_op_num) {
- ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
- ZEND_VM_CONTINUE();
- } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
- zend_generator *generator = zend_get_running_generator(execute_data);
- zend_generator_close(generator, 1);
- ZEND_VM_RETURN();
- } else {
- ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
- }
- }
+ ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, current_try_catch_offset, op_num, throw_op_num);
}
ZEND_VM_HANDLER(146, ZEND_VERIFY_ABSTRACT_CLASS, ANY, ANY)
@@ -7368,7 +7242,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY)
case ZEND_USER_OPCODE_CONTINUE:
ZEND_VM_CONTINUE();
case ZEND_USER_OPCODE_RETURN:
- if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
+ if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
zend_generator *generator = zend_get_running_generator(execute_data);
zend_generator_close(generator, 1);
ZEND_VM_RETURN();
@@ -7398,18 +7272,13 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
name = GET_OP1_ZVAL_PTR(BP_VAR_R);
val = GET_OP2_ZVAL_PTR(BP_VAR_R);
- ZVAL_COPY_VALUE(&c.value, val);
+ ZVAL_COPY(&c.value, val);
if (Z_OPT_CONSTANT(c.value)) {
- if (UNEXPECTED(zval_update_constant_ex(&c.value, 0, NULL) != SUCCESS)) {
+ if (UNEXPECTED(zval_update_constant_ex(&c.value, EX(func)->op_array.scope) != SUCCESS)) {
FREE_OP1();
FREE_OP2();
HANDLE_EXCEPTION();
}
- } else {
- /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
- if (UNEXPECTED(Z_OPT_COPYABLE(c.value))) {
- zval_copy_ctor_func(&c.value);
- }
}
c.flags = CONST_CS; /* non persistent, case sensetive */
c.name = zend_string_dup(Z_STR_P(name), 0);
@@ -7427,20 +7296,28 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
{
USE_OPLINE
zval *zfunc;
+ zval *object;
+ zend_class_entry *called_scope;
SAVE_OPLINE();
zfunc = zend_hash_find(EG(function_table), Z_STR_P(EX_CONSTANT(opline->op1)));
ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION);
- if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
+ if (Z_TYPE(EX(This)) == IS_OBJECT) {
+ called_scope = Z_OBJCE(EX(This));
+ if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
- zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
- EG(scope), EX(called_scope), NULL);
+ object = NULL;
+ } else {
+ object = &EX(This);
+ }
} else {
- zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
- EG(scope), EX(called_scope), Z_OBJ(EX(This)) ? &EX(This) : NULL);
+ called_scope = Z_CE(EX(This));
+ object = NULL;
}
+ zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
+ EX(func)->op_array.scope, called_scope, object);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
@@ -7455,10 +7332,8 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
if (UNEXPECTED(Z_REFCOUNT_P(var_ptr) == 1)) {
ZVAL_UNREF(var_ptr);
}
- } else if (Z_COPYABLE_P(var_ptr) && Z_REFCOUNT_P(var_ptr) > 1) {
- Z_DELREF_P(var_ptr);
- ZVAL_DUP(EX_VAR(opline->op1.var), var_ptr);
}
+
ZEND_VM_NEXT_OPCODE();
}
@@ -7497,8 +7372,8 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
value = GET_OP1_ZVAL_PTR(BP_VAR_R);
ZVAL_COPY_VALUE(&generator->value, value);
if (OP1_TYPE == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) {
- zval_copy_ctor_func(&generator->value);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED(generator->value))) {
+ Z_ADDREF(generator->value);
}
}
} else {
@@ -7509,7 +7384,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
if (OP1_TYPE == IS_VAR &&
(value_ptr == &EG(uninitialized_zval) ||
(opline->extended_value == ZEND_RETURNS_FUNCTION &&
- !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) {
+ !Z_ISREF_P(value_ptr)))) {
zend_error(E_NOTICE, "Only variable references should be yielded by reference");
} else {
ZVAL_MAKE_REF(value_ptr);
@@ -7524,8 +7399,8 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
/* Consts, temporary variables and references need copying */
if (OP1_TYPE == IS_CONST) {
ZVAL_COPY_VALUE(&generator->value, value);
- if (UNEXPECTED(Z_OPT_COPYABLE(generator->value))) {
- zval_copy_ctor_func(&generator->value);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED(generator->value))) {
+ Z_ADDREF(generator->value);
}
} else if (OP1_TYPE == IS_TMP_VAR) {
ZVAL_COPY_VALUE(&generator->value, value);
@@ -7552,8 +7427,8 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
/* Consts, temporary variables and references need copying */
if (OP2_TYPE == IS_CONST) {
ZVAL_COPY_VALUE(&generator->key, key);
- if (UNEXPECTED(Z_OPT_COPYABLE(generator->key))) {
- zval_copy_ctor_func(&generator->key);
+ if (UNEXPECTED(Z_OPT_REFCOUNTED(generator->key))) {
+ Z_ADDREF(generator->key);
}
} else if (OP2_TYPE == IS_TMP_VAR) {
ZVAL_COPY_VALUE(&generator->key, key);
@@ -7610,6 +7485,12 @@ ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY)
SAVE_OPLINE();
val = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
+ if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+ zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+ FREE_OP1();
+ HANDLE_EXCEPTION();
+ }
+
if (Z_TYPE_P(val) == IS_ARRAY) {
ZVAL_COPY_VALUE(&generator->values, val);
if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {
@@ -7695,77 +7576,57 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
{
USE_OPLINE
zval *fast_call = EX_VAR(opline->op1.var);
+ SAVE_OPLINE();
+
+ /* cleanup incomplete RETURN statement */
+ if (fast_call->u2.lineno != (uint32_t)-1
+ && (EX(func)->op_array.opcodes[fast_call->u2.lineno].op2_type & (IS_TMP_VAR | IS_VAR))) {
+ zval *return_value = EX_VAR(EX(func)->op_array.opcodes[fast_call->u2.lineno].op2.var);
+
+ zval_ptr_dtor(return_value);
+ }
- /* check for delayed exception */
+ /* cleanup delayed exception */
if (Z_OBJ_P(fast_call) != NULL) {
- SAVE_OPLINE();
/* discard the previously thrown exception */
OBJ_RELEASE(Z_OBJ_P(fast_call));
Z_OBJ_P(fast_call) = NULL;
}
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, TRY_CATCH, FAST_CALL)
+ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, ANY)
{
USE_OPLINE
zval *fast_call = EX_VAR(opline->result.var);
- if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY && UNEXPECTED(Z_OBJ_P(fast_call) != NULL)) {
- fast_call->u2.lineno = (uint32_t)-1;
- } else {
- Z_OBJ_P(fast_call) = NULL;
- /* set return address */
- fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
- }
+ Z_OBJ_P(fast_call) = NULL;
+ /* set return address */
+ fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op1));
ZEND_VM_CONTINUE();
}
-ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
+ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH)
{
USE_OPLINE
zval *fast_call = EX_VAR(opline->op1.var);
+ uint32_t current_try_catch_offset, current_op_num;
if (fast_call->u2.lineno != (uint32_t)-1) {
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
+
ZEND_VM_SET_OPCODE(fast_ret + 1);
- if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
- fast_call->u2.lineno = EX(func)->op_array.try_catch_array[fast_ret->op2.num].finally_op - 2;
- }
ZEND_VM_CONTINUE();
- } else {
- /* special case for unhandled exceptions */
- USE_OPLINE
-
- if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
- uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
-
- cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
- ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
- ZEND_VM_CONTINUE();
- } else {
- EG(exception) = Z_OBJ_P(fast_call);
- Z_OBJ_P(fast_call) = NULL;
- if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
- uint32_t catch_op = EX(func)->op_array.try_catch_array[opline->op2.num].catch_op;
-
- cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, catch_op);
- ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op]);
- ZEND_VM_CONTINUE();
- } else {
- cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
- if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
- zend_generator *generator = zend_get_running_generator(execute_data);
- zend_generator_close(generator, 1);
- ZEND_VM_RETURN();
- } else {
- ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
- }
- }
- }
}
+
+ /* special case for unhandled exceptions */
+ EG(exception) = Z_OBJ_P(fast_call);
+ Z_OBJ_P(fast_call) = NULL;
+ current_try_catch_offset = opline->op2.num;
+ current_op_num = opline - EX(func)->op_array.opcodes;
+ ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, current_try_catch_offset, op_num, current_op_num);
}
ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST)
@@ -7776,6 +7637,7 @@ ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST)
zval *value;
zval *variable_ptr;
uint32_t idx;
+ zend_reference *ref;
ZEND_VM_REPEATABLE_OPCODE
@@ -7818,32 +7680,27 @@ ZEND_VM_C_LABEL(check_indirect):
}
}
- do {
- zend_reference *ref;
+ if (UNEXPECTED(!Z_ISREF_P(value))) {
+ ref = (zend_reference*)emalloc(sizeof(zend_reference));
+ GC_REFCOUNT(ref) = 2;
+ GC_TYPE_INFO(ref) = IS_REFERENCE;
+ ZVAL_COPY_VALUE(&ref->val, value);
+ Z_REF_P(value) = ref;
+ Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
+ } else {
+ ref = Z_REF_P(value);
+ GC_REFCOUNT(ref)++;
+ }
- if (UNEXPECTED(!Z_ISREF_P(value))) {
- ref = (zend_reference*)emalloc(sizeof(zend_reference));
- GC_REFCOUNT(ref) = 2;
- GC_TYPE_INFO(ref) = IS_REFERENCE;
- ZVAL_COPY_VALUE(&ref->val, value);
- Z_REF_P(value) = ref;
- Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
- } else {
- ref = Z_REF_P(value);
- GC_REFCOUNT(ref)++;
- }
+ variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
-
- if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
- uint32_t refcnt = Z_DELREF_P(variable_ptr);
+ if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+ uint32_t refcnt = Z_DELREF_P(variable_ptr);
- if (UNEXPECTED(variable_ptr == value)) {
- break;
- }
+ if (EXPECTED(variable_ptr != value)) {
if (refcnt == 0) {
SAVE_OPLINE();
- zval_dtor_func_for_ptr(Z_COUNTED_P(variable_ptr));
+ zval_dtor_func(Z_COUNTED_P(variable_ptr));
if (UNEXPECTED(EG(exception))) {
ZVAL_NULL(variable_ptr);
HANDLE_EXCEPTION();
@@ -7852,8 +7709,8 @@ ZEND_VM_C_LABEL(check_indirect):
GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
}
}
- ZVAL_REF(variable_ptr, ref);
- } while (0);
+ }
+ ZVAL_REF(variable_ptr, ref);
ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
ZEND_VM_NEXT_OPCODE();
@@ -7975,12 +7832,14 @@ ZEND_VM_HANDLER(151, ZEND_ASSERT_CHECK, ANY, JMP_ADDR)
ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, ANY, ANY, CLASS_FETCH)
{
uint32_t fetch_type;
+ zend_class_entry *called_scope, *scope;
USE_OPLINE
SAVE_OPLINE();
fetch_type = opline->extended_value;
- if (UNEXPECTED(EG(scope) == NULL)) {
+ scope = EX(func)->op_array.scope;
+ if (UNEXPECTED(scope == NULL)) {
zend_throw_error(NULL, "Cannot use \"%s\" when no class scope is active",
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
@@ -7989,18 +7848,23 @@ ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, ANY, ANY, CLASS_FETCH)
switch (fetch_type) {
case ZEND_FETCH_CLASS_SELF:
- ZVAL_STR_COPY(EX_VAR(opline->result.var), EG(scope)->name);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), scope->name);
break;
case ZEND_FETCH_CLASS_PARENT:
- if (UNEXPECTED(EG(scope)->parent == NULL)) {
+ if (UNEXPECTED(scope->parent == NULL)) {
zend_throw_error(NULL,
"Cannot use \"parent\" when current class scope has no parent");
HANDLE_EXCEPTION();
}
- ZVAL_STR_COPY(EX_VAR(opline->result.var), EG(scope)->parent->name);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), scope->parent->name);
break;
case ZEND_FETCH_CLASS_STATIC:
- ZVAL_STR_COPY(EX_VAR(opline->result.var), EX(called_scope)->name);
+ if (Z_TYPE(EX(This)) == IS_OBJECT) {
+ called_scope = Z_OBJCE(EX(This));
+ } else {
+ called_scope = Z_CE(EX(This));
+ }
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), called_scope->name);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
@@ -8050,10 +7914,10 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
- call->symbol_table = NULL;
- i_init_func_execute_data(call, &fbc->op_array,
- ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
-
+ if (UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
+ i_init_func_execute_data(call, &fbc->op_array, ret);
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
@@ -8067,32 +7931,19 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
EG(current_execute_data) = call;
- if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
- uint32_t i;
- uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
- zval *p = ZEND_CALL_ARG(call, 1);
-
- EG(current_execute_data) = call;
-
- for (i = 0; i < num_args; ++i) {
- if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
- EG(current_execute_data) = call->prev_execute_data;
- zend_vm_stack_free_args(call);
- zend_vm_stack_free_call_frame(call);
- if (ret) {
- ZVAL_UNDEF(ret);
- }
- ZEND_VM_C_GOTO(call_trampoline_end);
- }
- p++;
+ if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
+ && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
+ zend_vm_stack_free_call_frame(call);
+ if (ret) {
+ ZVAL_UNDEF(ret);
}
+ ZEND_VM_C_GOTO(call_trampoline_end);
}
if (ret == NULL) {
ZVAL_NULL(&retval);
ret = &retval;
}
- Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */
@@ -8130,7 +7981,6 @@ ZEND_VM_C_LABEL(call_trampoline_end):
zend_object *object = Z_OBJ(call->This);
OBJ_RELEASE(object);
}
- EG(scope) = EX(func)->op_array.scope;
zend_vm_stack_free_call_frame(call);
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -8203,7 +8053,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
if (opline->extended_value) {
if (Z_CONSTANT_P(value)) {
- if (UNEXPECTED(zval_update_constant_ex(value, 1, NULL) != SUCCESS)) {
+ if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
ZVAL_NULL(variable_ptr);
HANDLE_EXCEPTION();
}
@@ -8227,4 +8077,530 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
+ZEND_VM_HANDLER(184, ZEND_FETCH_THIS, UNUSED, UNUSED)
+{
+ USE_OPLINE
+
+ if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
+ zval *result = EX_VAR(opline->result.var);
+
+ ZVAL_OBJ(result, Z_OBJ(EX(This)));
+ Z_ADDREF_P(result);
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ SAVE_OPLINE();
+ zend_throw_error(NULL, "Using $this when not in object context");
+ HANDLE_EXCEPTION();
+ }
+}
+
+ZEND_VM_HANDLER(186, ZEND_ISSET_ISEMPTY_THIS, UNUSED, UNUSED)
+{
+ USE_OPLINE
+
+ ZVAL_BOOL(EX_VAR(opline->result.var),
+ (opline->extended_value & ZEND_ISSET) ?
+ (Z_TYPE(EX(This)) == IS_OBJECT) :
+ (Z_TYPE(EX(This)) != IS_OBJECT));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ fast_long_add_function(result, op1, op2);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_ADD_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_SUB_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_SUB_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ fast_long_sub_function(result, op1, op2);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_SUB_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_MUL_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_LONG(result, Z_LVAL_P(op1) * Z_LVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_MUL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+ zend_long overflow;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow);
+ Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_MUL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2, *result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = EX_VAR(opline->result.var);
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_NOT_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_LVAL_P(op1) != Z_LVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_NOT_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_DVAL_P(op1) != Z_DVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_SMALLER_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_LVAL_P(op1) < Z_LVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_SMALLER_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_DVAL_P(op1) < Z_DVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_SMALLER_OR_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_LVAL_P(op1) <= Z_LVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_SMALLER_OR_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
+{
+ USE_OPLINE
+ zval *op1, *op2;
+ int result;
+
+ op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ result = (Z_DVAL_P(op1) <= Z_DVAL_P(op2));
+ ZEND_VM_SMART_BRANCH(result, 0);
+ ZVAL_BOOL(EX_VAR(opline->result.var), result);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_PRE_INC_LONG_NO_OVERFLOW, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ Z_LVAL_P(var_ptr)++;
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_INC_LONG, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ fast_long_increment_function(var_ptr);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_INC_LONG_OR_DOUBLE, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
+ fast_long_increment_function(var_ptr);
+ } else {
+ Z_DVAL_P(var_ptr)++;
+ }
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG_NO_OVERFLOW, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ Z_LVAL_P(var_ptr)--;
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ fast_long_decrement_function(var_ptr);
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_DEC_LONG_OR_DOUBLE, TMPVARCV, ANY, SPEC(RETVAL))
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
+ fast_long_decrement_function(var_ptr);
+ } else {
+ Z_DVAL_P(var_ptr)--;
+ }
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG_NO_OVERFLOW, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ Z_LVAL_P(var_ptr)++;
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ fast_long_increment_function(var_ptr);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_INC_LONG_OR_DOUBLE, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
+ fast_long_increment_function(var_ptr);
+ } else {
+ Z_DVAL_P(var_ptr)++;
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG_NO_OVERFLOW, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ Z_LVAL_P(var_ptr)--;
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
+ fast_long_decrement_function(var_ptr);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_DEC_LONG_OR_DOUBLE, TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zval *var_ptr;
+
+ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
+ if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
+ fast_long_decrement_function(var_ptr);
+ } else {
+ Z_DVAL_P(var_ptr)--;
+ }
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (op1_info == MAY_BE_DOUBLE), ZEND_QM_ASSIGN_DOUBLE, CONST|TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *value;
+
+ value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ ZVAL_DOUBLE(EX_VAR(opline->result.var), Z_DVAL_P(value));
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))), ZEND_QM_ASSIGN_NOREF, CONST|TMPVARCV, ANY)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *value;
+
+ value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))), ZEND_FETCH_DIM_R_INDEX, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
+{
+ USE_OPLINE
+ zend_free_op free_op1, free_op2;
+ zval *container, *dim, *value;
+ zend_long offset;
+
+ container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ZEND_VM_C_LABEL(fetch_dim_r_index_array):
+ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
+ offset = Z_LVAL_P(dim);
+ } else {
+ offset = zval_get_long(dim);
+ }
+ ZEND_HASH_INDEX_FIND(Z_ARRVAL_P(container), offset, value, ZEND_VM_C_LABEL(fetch_dim_r_index_undef));
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
+ SAVE_OPLINE();
+ FREE_OP1();
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+ } else {
+ ZEND_VM_NEXT_OPCODE();
+ }
+ } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
+ container = Z_REFVAL_P(container);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ ZEND_VM_C_GOTO(fetch_dim_r_index_array);
+ } else {
+ ZEND_VM_C_GOTO(fetch_dim_r_index_slow);
+ }
+ } else {
+ZEND_VM_C_LABEL(fetch_dim_r_index_slow):
+ SAVE_OPLINE();
+ zend_fetch_dimension_address_read_R_slow(EX_VAR(opline->result.var), container, dim);
+ FREE_OP1();
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+ }
+
+ZEND_VM_C_LABEL(fetch_dim_r_index_undef):
+ ZVAL_NULL(EX_VAR(opline->result.var));
+ SAVE_OPLINE();
+ zend_error(E_NOTICE, "Undefined offset: " ZEND_LONG_FMT, offset);
+ FREE_OP1();
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM)
+{
+ USE_OPLINE
+ zval *varptr, *arg;
+ zend_free_op free_op1;
+
+ varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ arg = ZEND_CALL_VAR(EX(call), opline->result.var);
+
+ if (OP1_TYPE == IS_CV) {
+ ZVAL_COPY(arg, varptr);
+ } else /* if (OP1_TYPE == IS_VAR) */ {
+ ZVAL_COPY_VALUE(arg, varptr);
+ }
+
+ ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, NUM, SPEC(QUICK_ARG))
+{
+ USE_OPLINE
+ zval *varptr, *arg;
+ zend_free_op free_op1;
+ uint32_t arg_num = opline->op2.num;
+
+ if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ ZEND_VM_C_GOTO(send_var_by_ref_simple);
+ }
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ZEND_VM_C_LABEL(send_var_by_ref_simple):
+ ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
+ }
+
+ varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
+ arg = ZEND_CALL_VAR(EX(call), opline->result.var);
+
+ if (OP1_TYPE == IS_CV) {
+ ZVAL_COPY(arg, varptr);
+ } else /* if (OP1_TYPE == IS_VAR) */ {
+ ZVAL_COPY_VALUE(arg, varptr);
+ }
+
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA);