diff options
Diffstat (limited to 'Zend/zend_vm_def.h')
| -rw-r--r-- | Zend/zend_vm_def.h | 2536 |
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); |
