]> granicus.if.org Git - php/commitdiff
Implemented HYBRID VM instruction dispatch method that takes advantages of both CALL...
authorDmitry Stogov <dmitry@zend.com>
Wed, 3 May 2017 07:01:22 +0000 (10:01 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 3 May 2017 07:01:22 +0000 (10:01 +0300)
Zend/zend_vm.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl
Zend/zend_vm_gen.php
Zend/zend_vm_opcodes.h
sapi/phpdbg/phpdbg_prompt.c

index c927c8fbe73f631f018dd18320a5a54f28f60165..cff9487ed321fa71ad1803a22b5234943315ff22 100644 (file)
@@ -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()
 
index 6823d61c2695cd32f5ba078b2d6ef2134c61d20a..8784adbe5951e28082dd6e17a25950b3755f5314 100644 (file)
@@ -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;
index 1e888d7b6a94362816044f0af7163e0a9b30401c..5ece46b0fd48a3bd71e77a761815d24dd203369b 100644 (file)
@@ -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[] = {
index 345d7bde7b26e07a901844b3963f2a6bfae01714..81397ce20bcfc267221ecfa83ecb2d16bc1ef01e 100644 (file)
@@ -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;
+}
+
index 7a45004e34bd8e82334813d02e973e9ac9e2980e..738e825381ca5c88932ccbd23f28a4c42b4d1fa2 100644 (file)
@@ -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();
index 2a0eb93aeb7c0b5f22fb23f0b8d5696a6449873f..a9d5b49648c7c5b5a02c679079f8a0d8af2e40e6 100644 (file)
@@ -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
index 544c973eecb2689e179443d8e4be4d0710196f13..88b0dad0b0e00a18c6a426de0cb0ecca0f4a6f00 100644 (file)
@@ -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