diff --git a/Zend/tests/021.phpt b/Zend/tests/021.phpt index 99fdb50258d..a40a41100ba 100644 --- a/Zend/tests/021.phpt +++ b/Zend/tests/021.phpt @@ -16,6 +16,12 @@ var_dump($a ?: $b); var_dump($c ?: $d); var_dump(1 ?: print(2)); + +$e = array(); + +$e['e'] = 'e'; +$e['e'] = $e['e'] ?: 'e'; +print_r($e); ?> --EXPECT-- bool(true) @@ -25,3 +31,7 @@ string(3) "bar" int(23) float(23.5) int(1) +Array +( + [e] => e +) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 31373c71c2b..761e56b3cca 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4332,6 +4332,43 @@ void zend_do_end_silence(znode *strudel_token TSRMLS_DC) } +void zend_do_jmp_set(znode *value, znode *jmp_token, znode *colon_token TSRMLS_DC) +{ + int op_number = get_next_op_number(CG(active_op_array)); + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_JMP_SET; + opline->result.op_type = IS_TMP_VAR; + opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->op1 = *value; + SET_UNUSED(opline->op2); + + *colon_token = opline->result; + + jmp_token->u.opline_num = op_number; + + INC_BPC(CG(active_op_array)); +} + + +void zend_do_jmp_set_else(znode *result, znode *false_value, znode *jmp_token, znode *colon_token TSRMLS_DC) +{ + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_QM_ASSIGN; + opline->extended_value = 0; + opline->result = *colon_token; + opline->op1 = *false_value; + SET_UNUSED(opline->op2); + + *result = opline->result; + + CG(active_op_array)->opcodes[jmp_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + + DEC_BPC(CG(active_op_array)); +} + + void zend_do_begin_qm_op(znode *cond, znode *qm_token TSRMLS_DC) { int jmpz_op_number = get_next_op_number(CG(active_op_array)); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b2ab1ae5abc..9056c1bb1db 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -491,6 +491,9 @@ void zend_do_exit(znode *result, znode *message TSRMLS_DC); void zend_do_begin_silence(znode *strudel_token TSRMLS_DC); void zend_do_end_silence(znode *strudel_token TSRMLS_DC); +void zend_do_jmp_set(znode *value, znode *jmp_token, znode *colon_token TSRMLS_DC); +void zend_do_jmp_set_else(znode *result, znode *false_value, znode *jmp_token, znode *colon_token TSRMLS_DC); + void zend_do_begin_qm_op(znode *cond, znode *qm_token TSRMLS_DC); void zend_do_qm_true(znode *true_value, znode *qm_token, znode *colon_token TSRMLS_DC); void zend_do_qm_false(znode *result, znode *false_value, znode *qm_token, znode *colon_token TSRMLS_DC); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c3169c430ad..fdff4d9accc 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1309,6 +1309,7 @@ void execute_new_code(TSRMLS_D) /* {{{ */ case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: + case ZEND_JMP_SET: opline->op2.u.jmp_addr = &CG(active_op_array)->opcodes[opline->op2.u.opline_num]; break; } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 2b32b3a35fe..343f81d3b38 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -611,9 +611,8 @@ expr_without_variable: | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } - | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } - ':' { zend_do_qm_true(&$1, &$2, &$4 TSRMLS_CC); } - expr { zend_do_qm_false(&$$, &$6, &$2, &$4 TSRMLS_CC); } + | expr '?' ':' { zend_do_jmp_set(&$1, &$2, &$3 TSRMLS_CC); } + expr { zend_do_jmp_set_else(&$$, &$5, &$2, &$3 TSRMLS_CC); } | internal_functions_in_yacc { $$ = $1; } | T_INT_CAST expr { zend_do_cast(&$$, &$2, IS_LONG TSRMLS_CC); } | T_DOUBLE_CAST expr { zend_do_cast(&$$, &$2, IS_DOUBLE TSRMLS_CC); } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index edabb98ada6..a30af32be5a 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -395,6 +395,7 @@ int pass_two(zend_op_array *op_array TSRMLS_DC) case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: + case ZEND_JMP_SET: opline->op2.u.jmp_addr = &op_array->opcodes[opline->op2.u.opline_num]; break; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ef18499924a..2597acec069 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3749,6 +3749,26 @@ ZEND_VM_HANDLER(58, ZEND_END_SILENCE, TMP, ANY) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, ANY) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (i_zend_is_true(value)) { + EX_T(opline->result.u.var).tmp_var = *value; + zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + FREE_OP1(); +#if DEBUG_ZEND>=2 + printf("Conditional jmp to %d\n", opline->op2.u.opline_num); +#endif + ZEND_VM_JMP(opline->op2.u.jmp_addr); + } + + FREE_OP1(); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) { zend_op *opline = EX(opline); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index e98a83f3241..5d9f3a2cae3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2101,6 +2101,25 @@ static int ZEND_EXIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_JMP_SET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *value = &opline->op1.u.constant; + + if (i_zend_is_true(value)) { + EX_T(opline->result.u.var).tmp_var = *value; + zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + +#if DEBUG_ZEND>=2 + printf("Conditional jmp to %d\n", opline->op2.u.opline_num); +#endif + ZEND_VM_JMP(opline->op2.u.jmp_addr); + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_QM_ASSIGN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -5198,6 +5217,26 @@ static int ZEND_END_SILENCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_JMP_SET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *value = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + + if (i_zend_is_true(value)) { + EX_T(opline->result.u.var).tmp_var = *value; + zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + zval_dtor(free_op1.var); +#if DEBUG_ZEND>=2 + printf("Conditional jmp to %d\n", opline->op2.u.opline_num); +#endif + ZEND_VM_JMP(opline->op2.u.jmp_addr); + } + + zval_dtor(free_op1.var); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_QM_ASSIGN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -8484,6 +8523,26 @@ static int ZEND_EXIT_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_JMP_SET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *value = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + + if (i_zend_is_true(value)) { + EX_T(opline->result.u.var).tmp_var = *value; + zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; +#if DEBUG_ZEND>=2 + printf("Conditional jmp to %d\n", opline->op2.u.opline_num); +#endif + ZEND_VM_JMP(opline->op2.u.jmp_addr); + } + + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_QM_ASSIGN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -21264,6 +21323,25 @@ static int ZEND_EXIT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_JMP_SET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *value = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); + + if (i_zend_is_true(value)) { + EX_T(opline->result.u.var).tmp_var = *value; + zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + +#if DEBUG_ZEND>=2 + printf("Conditional jmp to %d\n", opline->op2.u.opline_num); +#endif + ZEND_VM_JMP(opline->op2.u.jmp_addr); + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_QM_ASSIGN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -31709,6 +31787,56 @@ void zend_init_opcodes_handlers(void) ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_JMP_SET_SPEC_CONST_HANDLER, + ZEND_JMP_SET_SPEC_CONST_HANDLER, + ZEND_JMP_SET_SPEC_CONST_HANDLER, + ZEND_JMP_SET_SPEC_CONST_HANDLER, + ZEND_JMP_SET_SPEC_CONST_HANDLER, + ZEND_JMP_SET_SPEC_TMP_HANDLER, + ZEND_JMP_SET_SPEC_TMP_HANDLER, + ZEND_JMP_SET_SPEC_TMP_HANDLER, + ZEND_JMP_SET_SPEC_TMP_HANDLER, + ZEND_JMP_SET_SPEC_TMP_HANDLER, + ZEND_JMP_SET_SPEC_VAR_HANDLER, + ZEND_JMP_SET_SPEC_VAR_HANDLER, + ZEND_JMP_SET_SPEC_VAR_HANDLER, + ZEND_JMP_SET_SPEC_VAR_HANDLER, + ZEND_JMP_SET_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_JMP_SET_SPEC_CV_HANDLER, + ZEND_JMP_SET_SPEC_CV_HANDLER, + ZEND_JMP_SET_SPEC_CV_HANDLER, + ZEND_JMP_SET_SPEC_CV_HANDLER, + ZEND_JMP_SET_SPEC_CV_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 82fbeda4f45..d663ea6d555 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -148,3 +148,4 @@ #define ZEND_ISSET_ISEMPTY_PROP_OBJ 148 #define ZEND_HANDLE_EXCEPTION 149 #define ZEND_USER_OPCODE 150 +#define ZEND_JMP_SET 152