com php-src: Implemented HYBRID VM instruction dispatch method that takes advantages of both CALL and GOTO VMs.: Zend/zend_vm.h Zen d/zend_vm_def.h Zend/zend_vm_execute.h Zend/zen d_vm_execute.skl Zend/zend_vm_gen.php Zend/zend _vm_opcodes.h sapi/phpdbg/phpdbg_prompt.c

[email protected] (Dmitry Stogov)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    27e01cd918dd3309571aa3628e6139d436b10e18
Author:    Dmitry Stogov <[email protected]>         Wed, 3 May 2017 10:01:22 +0300
Parents:   9d6b7435e4fc0f84096164e91c5aade1cfe1ac96
Branches:  master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=27e01cd918dd3309571aa3628e6139d436b10e18

Log:
Implemented HYBRID VM instruction dispatch method that takes advantages of both CALL and GOTO VMs.

Changed paths:
  M  Zend/zend_vm.h
  M  Zend/zend_vm_def.h
  M  Zend/zend_vm_execute.h
  M  Zend/zend_vm_execute.skl
  M  Zend/zend_vm_gen.php
  M  Zend/zend_vm_opcodes.h
  M  sapi/phpdbg/phpdbg_prompt.c
diff_27e01cd918dd3309571aa3628e6139d436b10e18.txt (text/plain, 50.9 KB)
diff --git a/Zend/zend_vm.h b/Zend/zend_vm.h
index c927c8f..cff9487 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 6823d61..8784adb 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 1e888d7..5ece46b 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 345d7bd..81397ce 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 7a45004..738e825 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 2a0eb93..a9d5b49 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 544c973..88b0dad 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.