From 27e01cd918dd3309571aa3628e6139d436b10e18 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 3 May 2017 10:01:22 +0300 Subject: [PATCH] Implemented HYBRID VM instruction dispatch method that takes advantages of both CALL and GOTO VMs. --- Zend/zend_vm.h | 3 + Zend/zend_vm_def.h | 104 +++++++-------- Zend/zend_vm_execute.h | 32 +++++ Zend/zend_vm_execute.skl | 32 +++++ Zend/zend_vm_gen.php | 260 ++++++++++++++++++++++++++---------- Zend/zend_vm_opcodes.h | 1 + sapi/phpdbg/phpdbg_prompt.c | 2 +- 7 files changed, 310 insertions(+), 124 deletions(-) diff --git a/Zend/zend_vm.h b/Zend/zend_vm.h index c927c8fbe7..cff9487ed3 100644 --- a/Zend/zend_vm.h +++ b/Zend/zend_vm.h @@ -28,7 +28,10 @@ ZEND_API void zend_vm_set_opcode_handler(zend_op* opcode); ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* opcode, uint32_t op1_info, uint32_t op2_info, uint32_t res_info); ZEND_API void zend_serialize_opcode_handler(zend_op *op); ZEND_API void zend_deserialize_opcode_handler(zend_op *op); +ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op); +ZEND_API const zend_op *zend_get_real_exit_op(void); ZEND_API int zend_vm_call_opcode_handler(zend_execute_data *ex); +ZEND_API int zend_vm_kind(void); END_EXTERN_C() diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 6823d61c26..8784adbe59 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2478,7 +2478,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } } -ZEND_VM_HANDLER(42, ZEND_JMP, JMP_ADDR, ANY) +ZEND_VM_HOT_HANDLER(42, ZEND_JMP, JMP_ADDR, ANY) { USE_OPLINE @@ -2486,7 +2486,7 @@ ZEND_VM_HANDLER(42, ZEND_JMP, JMP_ADDR, ANY) ZEND_VM_CONTINUE(); } -ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMPVAR|CV, JMP_ADDR) +ZEND_VM_HOT_HANDLER(43, ZEND_JMPZ, CONST|TMPVAR|CV, JMP_ADDR) { USE_OPLINE zend_free_op free_op1; @@ -2518,7 +2518,7 @@ ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMPVAR|CV, JMP_ADDR) ZEND_VM_JMP(opline); } -ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) +ZEND_VM_HOT_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) { USE_OPLINE zend_free_op free_op1; @@ -2549,7 +2549,7 @@ ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) ZEND_VM_JMP(opline); } -ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMPVAR|CV, JMP_ADDR, JMP_ADDR) +ZEND_VM_HOT_HANDLER(45, ZEND_JMPZNZ, CONST|TMPVAR|CV, JMP_ADDR, JMP_ADDR) { USE_OPLINE zend_free_op free_op1; @@ -3191,7 +3191,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM) +ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM) { USE_OPLINE zend_function *fbc; @@ -3391,7 +3391,7 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM) +ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM) { USE_OPLINE zend_free_op free_op2; @@ -3424,7 +3424,7 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) +ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) { USE_OPLINE zend_execute_data *call = EX(call); @@ -3468,7 +3468,7 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) ZEND_VM_CONTINUE(); } -ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) +ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) { USE_OPLINE zend_execute_data *call = EX(call); @@ -3490,7 +3490,7 @@ ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) ZEND_VM_ENTER(); } -ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) +ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) { USE_OPLINE zend_execute_data *call = EX(call); @@ -3568,7 +3568,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) ZEND_VM_CONTINUE(); } -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) +ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) { USE_OPLINE zend_execute_data *call = EX(call); @@ -3743,7 +3743,7 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) +ZEND_VM_HOT_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zval *retval_ptr; @@ -4082,7 +4082,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR) } } -ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMPVAR, NUM) +ZEND_VM_HOT_HANDLER(65, ZEND_SEND_VAL, CONST|TMPVAR, NUM) { USE_OPLINE zval *value, *arg; @@ -4099,7 +4099,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMPVAR, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, NUM, SPEC(QUICK_ARG)) +ZEND_VM_HOT_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, NUM, SPEC(QUICK_ARG)) { USE_OPLINE zval *value, *arg; @@ -4130,7 +4130,7 @@ ZEND_VM_C_LABEL(send_val_by_ref): ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) +ZEND_VM_HOT_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) { USE_OPLINE zval *varptr, *arg; @@ -4257,7 +4257,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, NUM, SPEC(QUICK_ARG)) +ZEND_VM_HOT_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, NUM, SPEC(QUICK_ARG)) { USE_OPLINE zval *varptr, *arg; @@ -4574,7 +4574,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, NUM, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(64, ZEND_RECV_INIT, NUM, CONST) +ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST) { USE_OPLINE uint32_t arg_num; @@ -6699,7 +6699,7 @@ ZEND_VM_HANDLER(169, ZEND_COALESCE, CONST|TMP|VAR|CV, JMP_ADDR) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) +ZEND_VM_HOT_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; @@ -7528,7 +7528,7 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH) 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) +ZEND_VM_HOT_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -8102,7 +8102,7 @@ ZEND_VM_HANDLER(188, ZEND_SWITCH_STRING, CONST|TMPVAR|CV, CONST, JMP_ADDR) } } -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)) +ZEND_VM_HOT_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; @@ -8114,7 +8114,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8126,7 +8126,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_LONG && op2_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8138,7 +8138,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_DOUBLE && op2_info == MA 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)) +ZEND_VM_HOT_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; @@ -8150,7 +8150,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (res_info == MAY_BE_LONG && op1_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8162,7 +8162,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_LONG && op2_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8174,7 +8174,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_DOUBLE && op2_info == MA 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)) +ZEND_VM_HOT_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; @@ -8186,7 +8186,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (res_info == MAY_BE_LONG && op1_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8200,7 +8200,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_LONG && op2_info == MAY_ 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)) +ZEND_VM_HOT_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; @@ -8212,7 +8212,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_DOUBLE && op2_info == MA 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)) +ZEND_VM_HOT_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; @@ -8226,7 +8226,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_LONG && op2_info == 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)) +ZEND_VM_HOT_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; @@ -8240,7 +8240,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info 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)) +ZEND_VM_HOT_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; @@ -8254,7 +8254,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_LONG && op2_inf 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)) +ZEND_VM_HOT_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; @@ -8268,7 +8268,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_i 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)) +ZEND_VM_HOT_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; @@ -8282,7 +8282,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_LONG && op2_info 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)) +ZEND_VM_HOT_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; @@ -8296,7 +8296,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_DOUBLE && op2_inf 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)) +ZEND_VM_HOT_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; @@ -8310,7 +8310,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_LONG && 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)) +ZEND_VM_HOT_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; @@ -8324,7 +8324,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_DOUBLE & 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)) +ZEND_VM_HOT_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; @@ -8337,7 +8337,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (res_info == MAY_BE_LONG && op1_info == 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)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_INC_LONG, TMPVARCV, ANY, SPEC(RETVAL)) { USE_OPLINE zval *var_ptr; @@ -8350,7 +8350,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_INC_ 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)) +ZEND_VM_HOT_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; @@ -8367,7 +8367,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE) 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)) +ZEND_VM_HOT_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; @@ -8380,7 +8380,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (res_info == MAY_BE_LONG && op1_info == 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)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG, TMPVARCV, ANY, SPEC(RETVAL)) { USE_OPLINE zval *var_ptr; @@ -8393,7 +8393,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_DEC_ 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)) +ZEND_VM_HOT_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; @@ -8410,7 +8410,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE) 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) +ZEND_VM_HOT_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; @@ -8421,7 +8421,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (res_info == MAY_BE_LONG && op1_info == ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG, TMPVARCV, ANY) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG, TMPVARCV, ANY) { USE_OPLINE zval *var_ptr; @@ -8432,7 +8432,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POST_IN 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) +ZEND_VM_HOT_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; @@ -8447,7 +8447,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE 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) +ZEND_VM_HOT_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; @@ -8458,7 +8458,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (res_info == MAY_BE_LONG && op1_info == ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG, TMPVARCV, ANY) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG, TMPVARCV, ANY) { USE_OPLINE zval *var_ptr; @@ -8469,7 +8469,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POST_DE 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) +ZEND_VM_HOT_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; @@ -8484,7 +8484,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (op1_info == MAY_BE_DOUBLE), ZEND_QM_ASSIGN_DOUBLE, CONST|TMPVARCV, ANY) +ZEND_VM_HOT_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; @@ -8495,7 +8495,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (op1_info == MAY_BE_DOUBLE), ZEND_QM_A 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) +ZEND_VM_HOT_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; @@ -8506,7 +8506,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDE 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) +ZEND_VM_HOT_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; @@ -8554,7 +8554,7 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_undef): 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) +ZEND_VM_HOT_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; @@ -8572,7 +8572,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) 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)) +ZEND_VM_HOT_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; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1e888d7b6a..5ece46b0fd 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -59177,6 +59177,38 @@ ZEND_API void zend_deserialize_opcode_handler(zend_op *op) op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler]; } +ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op) +{ +#if ZEND_VM_KIND == ZEND_VM_KIND_CALL + return op->handler; +#elif ZEND_VM_KIND == ZEND_VM_KIND_HYBRID + zval *zv; + + if (!zend_handlers_table) { + init_opcode_serialiser(); + } + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + ZEND_ASSERT(zv != NULL); + return zend_opcode_real_handlers[Z_LVAL_P(zv)]; +#else + return NULL; +#endif +} + +ZEND_API const zend_op *zend_get_real_exit_op(void) +{ +#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID + return &hybrid_return_op; +#else + return NULL; +#endif +} + +ZEND_API int zend_vm_kind(void) +{ + return ZEND_VM_KIND; +} + static const void *zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* op) { static const int zend_vm_decode[] = { diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 345d7bde7b..81397ce20b 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -83,3 +83,35 @@ ZEND_API void zend_deserialize_opcode_handler(zend_op *op) op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler]; } +ZEND_API const void *zend_get_real_opcode_handler(const zend_op *op) +{ +#if ZEND_VM_KIND == ZEND_VM_KIND_CALL + return op->handler; +#elif ZEND_VM_KIND == ZEND_VM_KIND_HYBRID + zval *zv; + + if (!zend_handlers_table) { + init_opcode_serialiser(); + } + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + ZEND_ASSERT(zv != NULL); + return zend_opcode_real_handlers[Z_LVAL_P(zv)]; +#else + return NULL; +#endif +} + +ZEND_API const zend_op *zend_get_real_exit_op(void) +{ +#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID + return &hybrid_return_op; +#else + return NULL; +#endif +} + +ZEND_API int zend_vm_kind(void) +{ + return ZEND_VM_KIND; +} + diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 7a45004e34..738e825381 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -53,6 +53,7 @@ error_reporting(E_ALL); const ZEND_VM_KIND_CALL = 1; const ZEND_VM_KIND_SWITCH = 2; const ZEND_VM_KIND_GOTO = 3; +const ZEND_VM_KIND_HYBRID = 4; $vm_op_flags = array( "ZEND_VM_OP_SPEC" => 1<<0, @@ -134,6 +135,7 @@ $vm_kind_name = array( ZEND_VM_KIND_CALL => "ZEND_VM_KIND_CALL", ZEND_VM_KIND_SWITCH => "ZEND_VM_KIND_SWITCH", ZEND_VM_KIND_GOTO => "ZEND_VM_KIND_GOTO", + ZEND_VM_KIND_HYBRID => "ZEND_VM_KIND_HYBRID", ); $op_types = array( @@ -885,7 +887,7 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name, $extra_sp if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { return "execute_data"; } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { - return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_HANDLER"; + return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_LABEL"; } else { // ZEND_VM_DISPATCH_TO_HELPER if (isset($matches[2])) { @@ -973,7 +975,7 @@ function skip_extra_spec_function($op1, $op2, $extra_spec) { } // Generates opcode handler -function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $extra_spec = null, &$switch_labels = array()) { +function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $opcode, $extra_spec = null, &$switch_labels = array()) { global $definition_file, $prefix, $typecode, $opnames; if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { @@ -987,8 +989,17 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, // Generate opcode handler's entry point according to selected threading model $spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):""); switch($kind) { + case ZEND_VM_KIND_HYBRID: + out($f,"\t\t\tHYBRID_CASE({$spec_name}):\n"); + out($f,"\t\t\t\t{$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"\t\t\t\tHYBRID_BREAK();\n"); + return; case ZEND_VM_KIND_CALL: - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + if ($opcode["hot"] && ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f,"static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + } else { + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + } break; case ZEND_VM_KIND_SWITCH: if ($spec) { @@ -1006,7 +1017,7 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, } break; case ZEND_VM_KIND_GOTO: - out($f,"{$spec_name}_HANDLER: ZEND_VM_GUARD($spec_name);\n"); + out($f,"{$spec_name}_LABEL: ZEND_VM_GUARD($spec_name);\n"); break; } @@ -1018,6 +1029,10 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, $inline, $extra_spec = null) { global $definition_file, $prefix; + if ($kind == ZEND_VM_KIND_HYBRID) { + return; + } + if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { return; } @@ -1068,7 +1083,7 @@ function gen_null_label($f, $kind, $prolog) { out($f,$prolog."(void*)(uintptr_t)-1,\n"); break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); break; } } @@ -1219,7 +1234,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array() $label++; break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&{$spec_name}_HANDLER,\n"); + out($f,$prolog."(void*)&&{$spec_name}_LABEL,\n"); $label++; break; } @@ -1265,7 +1280,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array() out($f,$prolog."(void*)(uintptr_t)-1,\n"); break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); break; } $next++; @@ -1286,7 +1301,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array() out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n"); break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&".$dsc["op"]."_HANDLER,\n"); + out($f,$prolog."(void*)&&".$dsc["op"]."_LABEL,\n"); break; } } else { @@ -1298,7 +1313,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array() out($f,$prolog."(void*)(uintptr_t)-1,\n"); break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); break; } } @@ -1314,14 +1329,14 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array() out($f,$prolog."(void*)(uintptr_t)-1\n"); break; case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_HANDLER\n"); + out($f,$prolog."(void*)&&ZEND_NULL_LABEL\n"); break; } $specs[$num + 1] = "$label"; } // Generates specialized offsets -function gen_specs($f, $spec, $kind, $prolog, $specs) { +function gen_specs($f, $prolog, $specs) { $lastdef = array_pop($specs); $last = 0; foreach ($specs as $num => $def) { @@ -1462,7 +1477,7 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) if (isset($opcodes[$num]["op1"][$op1]) && isset($opcodes[$num]["op2"][$op2])) { // Generate handler code - gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $extra_spec, $switch_labels); + gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num], $extra_spec, $switch_labels); } } } else if (isset($dsc["helper"])) { @@ -1491,7 +1506,7 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) $num = $dsc["handler"]; // Generate handler code if ($num < 256) { - gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno); + gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num]); } } else if (isset($dsc["helper"])) { $num = $dsc["helper"]; @@ -1520,10 +1535,19 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); break; case ZEND_VM_KIND_GOTO: - out($f,"ZEND_NULL_HANDLER:\n"); + out($f,"ZEND_NULL_LABEL:\n"); out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); break; + case ZEND_VM_KIND_HYBRID: + out($f,"\t\t\tHYBRID_CASE(HYBRID_RETURN):\n"); + out($f,"\t\t\t\texecute_data = orig_execute_data;\n"); + out($f,"\t\t\t\topline = orig_opline;\n"); + out($f,"\t\t\t\treturn;\n"); + out($f,"\t\t\tHYBRID_DEFAULT:\n"); + out($f,"\t\t\t\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); + out($f,"\t\t\t\tHYBRID_BREAK(); /* Never reached */\n"); + break; } } @@ -1557,8 +1581,22 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"static const uint32_t *zend_spec_handlers;\n"); out($f,"static const void **zend_opcode_handlers;\n"); out($f,"static int zend_handlers_count;\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"static const void **zend_opcode_real_handlers;\n"); + out($f,"static zend_op hybrid_return_op;\n"); + out($f,"#endif\n"); + } out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n"); switch ($kind) { + case ZEND_VM_KIND_HYBRID: + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"#define HYBRID_NEXT() goto *(void**)(OPLINE->handler)\n"); + out($f,"#define HYBRID_SWITCH() HYBRID_NEXT();\n"); + out($f,"#define HYBRID_CASE(op) op ## _LABEL\n"); + out($f,"#define HYBRID_BREAK() HYBRID_NEXT()\n"); + out($f,"#define HYBRID_DEFAULT ZEND_NULL_LABEL\n"); + out($f,"#endif\n"); case ZEND_VM_KIND_CALL: out($f,"\n"); out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); @@ -1593,7 +1631,17 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# else\n"); out($f,"# define ZEND_VM_CONTINUE() return\n"); out($f,"# endif\n"); - out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"# if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"# define ZEND_VM_RETURN() opline = &hybrid_return_op; return\n"); + out($f,"# define ZEND_VM_HOT zend_always_inline\n"); + out($f,"# else\n"); + out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); + out($f,"# define ZEND_VM_HOT\n"); + out($f,"# endif\n"); + } else { + out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); + } out($f,"#else\n"); out($f,"# define ZEND_OPCODE_HANDLER_RET int\n"); out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n"); @@ -1696,11 +1744,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#undef HANDLE_EXCEPTION\n"); out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); if (ZEND_VM_SPEC) { - out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); + out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); } else { - out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_HANDLER\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_HANDLER\n"); + out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); } out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); out($f,"#define ZEND_VM_RETURN() return\n"); @@ -1712,12 +1760,15 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"\n"); break; } + if ($kind == ZEND_VM_KIND_HYBRID) { + gen_executor_code($f, $spec, ZEND_VM_KIND_CALL, $m[1]); + } break; case "EXECUTOR_NAME": out($f, $m[1].$executor_name.$m[3]."\n"); break; case "HELPER_VARS": - if ($kind != ZEND_VM_KIND_CALL) { + if ($kind != ZEND_VM_KIND_CALL && $kind != ZEND_VM_KIND_HYBRID) { if ($kind == ZEND_VM_KIND_SWITCH) { out($f,$m[1]."const void *dispatch_handler;\n"); } @@ -1743,28 +1794,36 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) } break; case "INTERNAL_LABELS": - if ($kind == ZEND_VM_KIND_GOTO) { + if ($kind == ZEND_VM_KIND_GOTO || $kind == ZEND_VM_KIND_HYBRID) { // Emit array of labels of opcode handlers and code for // zend_opcode_handlers initialization + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + } $prolog = $m[1]; out($f,$prolog."if (UNEXPECTED(execute_data == NULL)) {\n"); out($f,$prolog."\tstatic const void* labels[] = {\n"); - gen_labels($f, $spec, $kind, $prolog."\t\t", $specs); + gen_labels($f, $spec, ZEND_VM_KIND_GOTO, $prolog."\t\t", $specs); out($f,$prolog."\t};\n"); - out($f,$prolog."static const uint32_t specs[] = {\n"); - gen_specs($f, $spec, $kind, $prolog."\t", $specs); - out($f,$prolog."};\n"); out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n"); out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n"); - out($f,$prolog."\tzend_spec_handlers = (const uint32_t *) specs;\n"); - out($f,$prolog."\treturn;\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,$prolog."\tmemset(&hybrid_return_op, 0, sizeof(hybrid_return_op));\n"); + out($f,$prolog."\thybrid_return_op.handler = (void*)&&HYBRID_RETURN_LABEL;\n"); + out($f,$prolog."\tgoto HYBRID_RETURN_LABEL;\n"); + } else { + out($f,$prolog."\treturn;\n"); + } out($f,$prolog."}\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } } else { skip_blanks($f, $m[1], $m[3]); } break; case "ZEND_VM_CONTINUE_LABEL": - if ($kind == ZEND_VM_KIND_CALL) { + if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { // Only SWITCH dispatch method use it out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n"); out($f,$m[1]."\tint ret;".$m[3]."\n"); @@ -1779,6 +1838,16 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) case "ZEND_VM_DISPATCH": // Emit code that dispatches to opcode handler switch ($kind) { + case ZEND_VM_KIND_SWITCH: + out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); + break; + case ZEND_VM_KIND_HYBRID: + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, $m[1]."HYBRID_SWITCH();".$m[3]."\n"); + out($f,"#else\n"); case ZEND_VM_KIND_CALL: out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); @@ -1786,18 +1855,25 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#else\n"); out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n"); out($f,"#endif\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } break; } break; case "INTERNAL_EXECUTOR": - if ($kind == ZEND_VM_KIND_CALL) { - // Executor is defined as a set of functions + if ($kind != ZEND_VM_KIND_CALL) { + // Emit executor code + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + } + gen_executor_code($f, $spec, $kind, $m[1], $switch_labels); + } + if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { + // Executor is defined as a set of functions + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#else\n"); + } out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . $m[1]."execute_data = orig_execute_data;\n" . @@ -1816,9 +1892,9 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) $m[1]."\treturn;\n". $m[1]."}\n". "#endif\n"); - } else { - // Emit executor code - gen_executor_code($f, $spec, $kind, $m[1], $switch_labels); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } } break; case "EXTERNAL_EXECUTOR": @@ -1835,18 +1911,31 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) if ($kind == ZEND_VM_KIND_GOTO) { // Labels are defined in the executor itself, so we call it // with execute_data NULL and it sets zend_opcode_handlers array - out($f,$prolog.""); + out($f,$prolog."static const uint32_t specs[] = {\n"); + gen_specs($f, $prolog."\t", $specs); + out($f,$prolog."};\n"); + out($f,$prolog."zend_spec_handlers = specs;\n"); out($f,$prolog.$executor_name."_ex(NULL);\n"); } else { out($f,$prolog."static const void *labels[] = {\n"); - gen_labels($f, $spec, $kind, $prolog."\t", $specs, $switch_labels); + gen_labels($f, $spec, ZEND_VM_KIND_CALL, $prolog."\t", $specs, $switch_labels); out($f,$prolog."};\n"); out($f,$prolog."static const uint32_t specs[] = {\n"); - gen_specs($f, $spec, $kind, $prolog."\t", $specs); + gen_specs($f, $prolog."\t", $specs); out($f,$prolog."};\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,$prolog."zend_opcode_real_handlers = labels;\n"); + out($f,$prolog."zend_spec_handlers = specs;\n"); + out($f,$prolog.$executor_name."_ex(NULL);\n"); + out($f,"#else\n"); + } out($f,$prolog."zend_opcode_handlers = labels;\n"); out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n"); out($f,$prolog."zend_spec_handlers = specs;\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } } break; default: @@ -1973,22 +2062,24 @@ function gen_vm($def, $skel) { $export = array(); foreach ($in as $line) { ++$lineno; - if (strpos($line,"ZEND_VM_HANDLER(") === 0) { + if (strpos($line,"ZEND_VM_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_HANDLER(") === 0) { // Parsing opcode handler's definition if (preg_match( - "/^ZEND_VM_HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", + "/^ZEND_VM_(HOT_)?HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", $line, $m) == 0) { die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n"); } - $code = (int)$m[1]; - $op = $m[2]; + $hot = !empty($m[1]); + $code = (int)$m[2]; + $op = $m[3]; $len = strlen($op); - $op1 = parse_operand_spec($def, $lineno, $m[3], $flags1); - $op2 = parse_operand_spec($def, $lineno, $m[4], $flags2); + $op1 = parse_operand_spec($def, $lineno, $m[4], $flags1); + $op2 = parse_operand_spec($def, $lineno, $m[5], $flags2); $flags = $flags1 | ($flags2 << 8); - if (!empty($m[6])) { - $flags |= parse_ext_spec($def, $lineno, $m[6]); + if (!empty($m[7])) { + $flags |= parse_ext_spec($def, $lineno, $m[7]); } if ($len > $max_opcode_len) { @@ -2003,9 +2094,9 @@ function gen_vm($def, $skel) { if (isset($opnames[$op])) { die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); } - $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags); - if (isset($m[8])) { - $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[8]); + $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot); + if (isset($m[9])) { + $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]); if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; } @@ -2017,27 +2108,29 @@ function gen_vm($def, $skel) { $handler = $code; $helper = null; $list[$lineno] = array("handler"=>$handler); - } else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0) { + } else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_TYPE_SPEC_HANDLER(") === 0) { // Parsing opcode handler's definition if (preg_match( - "/^ZEND_VM_TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*([^,]+),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", + "/^ZEND_VM_(HOT_)?TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*([^,]+),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", $line, $m) == 0) { die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n"); } - $orig_op = $m[1]; + $hot = !empty($m[1]); + $orig_op = $m[2]; if (!isset($opnames[$orig_op])) { die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n"); } $orig_code = $opnames[$orig_op]; - $condition = $m[2]; + $condition = $m[3]; $code = $extra_num++; - $op = $m[3]; - $op1 = parse_operand_spec($def, $lineno, $m[4], $flags1); - $op2 = parse_operand_spec($def, $lineno, $m[5], $flags2); + $op = $m[4]; + $op1 = parse_operand_spec($def, $lineno, $m[5], $flags1); + $op2 = parse_operand_spec($def, $lineno, $m[6], $flags2); $flags = $flags1 | ($flags2 << 8); - if (!empty($m[7])) { - $flags |= parse_ext_spec($def, $lineno, $m[7]); + if (!empty($m[8])) { + $flags |= parse_ext_spec($def, $lineno, $m[8]); } if (isset($opcodes[$code])) { @@ -2045,9 +2138,9 @@ function gen_vm($def, $skel) { } $opcodes[$orig_code]['type_spec'][$code] = $condition; $used_extra_spec["TYPE"] = 1; - $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags); - if (isset($m[9])) { - $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]); + $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot); + if (isset($m[10])) { + $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]); if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; } @@ -2174,7 +2267,17 @@ function gen_vm($def, $skel) { fputs($f, "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n"); fputs($f, "#define ZEND_VM_KIND_SWITCH\t" . ZEND_VM_KIND_SWITCH . "\n"); fputs($f, "#define ZEND_VM_KIND_GOTO\t" . ZEND_VM_KIND_GOTO . "\n"); - fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n"); + fputs($f, "#define ZEND_VM_KIND_HYBRID\t" . ZEND_VM_KIND_HYBRID . "\n"); + if ($GLOBALS["vm_kind_name"][ZEND_VM_KIND] === "ZEND_VM_KIND_HYBRID") { + fputs($f, "/* HYBRID requires support for cmputed GOTO and global register variables*/\n"); + fputs($f, "#if (defined(__GNUC__) && defined(HAVE_GCC_GLOBAL_REGS))\n"); + fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_HYBRID\n"); + fputs($f, "#else\n"); + fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_CALL\n"); + fputs($f, "#endif\n"); + } else { + fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n"); + } fputs($f, "\n"); foreach($vm_op_flags as $name => $val) { fprintf($f, "#define %-24s 0x%08x\n", $name, $val); @@ -2405,9 +2508,14 @@ function gen_vm($def, $skel) { out($f, "}\n\n"); // Generate zend_vm_call_opcode_handler() function - if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) { + if (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); out($f, "{\n"); + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, "\topcode_handler_t handler;\n"); + out($f,"#endif\n"); + } out($f, "\tint ret;\n"); out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); out($f, "\tconst zend_op *orig_opline = opline;\n"); @@ -2420,7 +2528,14 @@ function gen_vm($def, $skel) { out($f, "#endif\n"); out($f, "\n"); out($f, "\tLOAD_OPLINE();\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, "\thandler = (opcode_handler_t)zend_get_real_opcode_handler(opline);\n"); + out($f, "\thandler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"#elif defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + } else { + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + } out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); out($f, "\tif (EXPECTED(opline)) {\n"); out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); @@ -2523,9 +2638,9 @@ function gen_vm($def, $skel) { function usage() { echo("\nUsage: php zend_vm_gen.php [options]\n". "\nOptions:". - "\n --with-vm-kind=CALL|SWITCH|GOTO - select threading model (default is CALL)". - "\n --without-specializer - disable executor specialization". - "\n --with-lines - enable #line directives". + "\n --with-vm-kind=CALL|SWITCH|GOTO|HYBRID - select threading model (default is CALL)". + "\n --without-specializer - disable executor specialization". + "\n --with-lines - enable #line directives". "\n\n"); } @@ -2543,6 +2658,9 @@ for ($i = 1; $i < $argc; $i++) { case "GOTO": define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO); break; + case "HYBRID": + define("ZEND_VM_KIND", ZEND_VM_KIND_HYBRID); + break; default: echo("ERROR: Invalid vm kind '$kind'\n"); usage(); diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 2a0eb93aeb..a9d5b49648 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -26,6 +26,7 @@ #define ZEND_VM_KIND_CALL 1 #define ZEND_VM_KIND_SWITCH 2 #define ZEND_VM_KIND_GOTO 3 +#define ZEND_VM_KIND_HYBRID 4 #define ZEND_VM_KIND ZEND_VM_KIND_CALL #define ZEND_VM_OP_SPEC 0x00000001 diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 544c973eec..88b0dad0b0 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -46,7 +46,7 @@ #include "phpdbg_wait.h" #include "phpdbg_eol.h" -#if ZEND_VM_KIND != ZEND_VM_KIND_CALL +#if ZEND_VM_KIND != ZEND_VM_KIND_CALL && ZEND_VM_KIND != ZEND_VM_KIND_HYBRID #error "phpdbg can only be built with CALL zend vm kind" #endif -- 2.40.0