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