Skip to content

Instantly share code, notes, and snippets.

@laruence
Created July 13, 2014 04:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save laruence/cf0267b1c13815ac635b to your computer and use it in GitHub Desktop.
Save laruence/cf0267b1c13815ac635b to your computer and use it in GitHub Desktop.
zend type check
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 56d0d97..90d36b1 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2751,6 +2751,54 @@ static int zend_do_convert_strlen(zend_op *init_opline, znode *result TSRMLS_DC)
}
/* }}} */
+static int zend_do_convert_type_check(zend_op *init_opline, znode *result, zend_uint type TSRMLS_DC) /* {{{ */
+{
+ zend_op *opline = init_opline + 1;
+ zend_op *send = NULL;
+ int level = 0;
+
+ do {
+ switch (opline->opcode) {
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAL_EX:
+ case ZEND_SEND_VAR:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_REF:
+ case ZEND_SEND_UNPACK:
+ if (level == 0) {
+ if (opline->opcode == ZEND_SEND_UNPACK) {
+ return 0;
+ }
+ send = opline;
+ }
+ break;
+ case ZEND_INIT_FCALL_BY_NAME:
+ case ZEND_INIT_NS_FCALL_BY_NAME:
+ case ZEND_NEW:
+ case ZEND_INIT_METHOD_CALL:
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ case ZEND_INIT_FCALL:
+ level++;
+ break;
+ case ZEND_DO_FCALL:
+ level--;
+ break;
+ }
+ opline++;
+ } while (send == NULL);
+
+ MAKE_NOP(init_opline);
+ send->opcode = ZEND_TYPE_CHECK;
+ send->extended_value = type;
+ SET_UNUSED(send->op2);
+ send->result.var = get_temporary_variable(CG(active_op_array));
+ send->result_type = IS_TMP_VAR;
+ GET_NODE(result, send->result);
+ return 1;
+}
+/* }}} */
+
void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
{
zend_op *opline;
@@ -2797,6 +2845,70 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho
return;
}
}
+ } else if (func->common.function_name->len == sizeof("is_null")-1 &&
+ memcmp(func->common.function_name->val, "is_null", sizeof("is_null")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_NULL)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_bool")-1 &&
+ memcmp(func->common.function_name->val, "is_bool", sizeof("is_bool")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, _IS_BOOL)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_long")-1 &&
+ memcmp(func->common.function_name->val, "is_long", sizeof("is_long")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_LONG)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_float")-1 &&
+ memcmp(func->common.function_name->val, "is_float", sizeof("is_float")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_DOUBLE)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_string")-1 &&
+ memcmp(func->common.function_name->val, "is_string", sizeof("is_string")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_STRING)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_array")-1 &&
+ memcmp(func->common.function_name->val, "is_array", sizeof("is_array")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_ARRAY)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_object")-1 &&
+ memcmp(func->common.function_name->val, "is_object", sizeof("is_object")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_OBJECT)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
+ } else if (func->common.function_name->len == sizeof("is_resouce")-1 &&
+ memcmp(func->common.function_name->val, "is_resource", sizeof("is_resource")-1) == 0) {
+ if (fcall->arg_num == 1) {
+ if (zend_do_convert_type_check(opline, result, IS_RESOURCE)) {
+ zend_stack_del_top(&CG(function_call_stack));
+ return;
+ }
+ }
}
}
}
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index dfe6651..93c6795 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5884,4 +5884,55 @@ ZEND_VM_C_LABEL(strlen_error):
ZEND_VM_NEXT_OPCODE();
}
+ZEND_VM_HANDLER(123, ZEND_TYPE_CHECK, CONST|TMP|VAR|CV, ANY)
+{
+ USE_OPLINE
+ zval *value;
+ zend_free_op free_op1;
+
+ SAVE_OPLINE();
+ value = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
+ switch (opline->extended_value) {
+ case IS_NULL:
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_ARRAY:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == opline->extended_value);
+ break;
+ case _IS_BOOL:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == IS_TRUE || Z_TYPE_P(value) == IS_FALSE);
+ break;
+ case IS_OBJECT:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ if (Z_OBJ_HT_P(value)->get_class_entry == NULL) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(value);
+ if (ce->name->len == sizeof("__PHP_Incomplete_Class") - 1
+ && !strncmp(ce->name->val, "__PHP_Incomplete_Class", ce->name->len)) {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ } else {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
+ }
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ break;
+ case IS_RESOURCE:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(value) TSRMLS_CC);
+ ZVAL_BOOL(EX_VAR(opline->result.var), type_name != NULL);
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+ FREE_OP1();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_EXPORT_HANDLER(zend_do_fcall, ZEND_DO_FCALL)
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index ecd15ff..dab0fc5 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3399,6 +3399,57 @@ strlen_error:
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zval *value;
+
+
+ SAVE_OPLINE();
+ value = opline->op1.zv;
+ switch (opline->extended_value) {
+ case IS_NULL:
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_ARRAY:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == opline->extended_value);
+ break;
+ case _IS_BOOL:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == IS_TRUE || Z_TYPE_P(value) == IS_FALSE);
+ break;
+ case IS_OBJECT:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ if (Z_OBJ_HT_P(value)->get_class_entry == NULL) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(value);
+ if (ce->name->len == sizeof("__PHP_Incomplete_Class") - 1
+ && !strncmp(ce->name->val, "__PHP_Incomplete_Class", ce->name->len)) {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ } else {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
+ }
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ break;
+ case IS_RESOURCE:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(value) TSRMLS_CC);
+ ZVAL_BOOL(EX_VAR(opline->result.var), type_name != NULL);
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -8880,6 +8931,57 @@ strlen_error:
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zval *value;
+ zend_free_op free_op1;
+
+ SAVE_OPLINE();
+ value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
+ switch (opline->extended_value) {
+ case IS_NULL:
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_ARRAY:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == opline->extended_value);
+ break;
+ case _IS_BOOL:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == IS_TRUE || Z_TYPE_P(value) == IS_FALSE);
+ break;
+ case IS_OBJECT:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ if (Z_OBJ_HT_P(value)->get_class_entry == NULL) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(value);
+ if (ce->name->len == sizeof("__PHP_Incomplete_Class") - 1
+ && !strncmp(ce->name->val, "__PHP_Incomplete_Class", ce->name->len)) {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ } else {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
+ }
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ break;
+ case IS_RESOURCE:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(value) TSRMLS_CC);
+ ZVAL_BOOL(EX_VAR(opline->result.var), type_name != NULL);
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+ zval_dtor(free_op1.var);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -14377,6 +14479,57 @@ strlen_error:
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zval *value;
+ zend_free_op free_op1;
+
+ SAVE_OPLINE();
+ value = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
+ switch (opline->extended_value) {
+ case IS_NULL:
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_ARRAY:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == opline->extended_value);
+ break;
+ case _IS_BOOL:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == IS_TRUE || Z_TYPE_P(value) == IS_FALSE);
+ break;
+ case IS_OBJECT:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ if (Z_OBJ_HT_P(value)->get_class_entry == NULL) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(value);
+ if (ce->name->len == sizeof("__PHP_Incomplete_Class") - 1
+ && !strncmp(ce->name->val, "__PHP_Incomplete_Class", ce->name->len)) {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ } else {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
+ }
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ break;
+ case IS_RESOURCE:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(value) TSRMLS_CC);
+ ZVAL_BOOL(EX_VAR(opline->result.var), type_name != NULL);
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+ zval_ptr_dtor_nogc(free_op1.var);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_ADD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -31488,6 +31641,57 @@ strlen_error:
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zval *value;
+
+
+ SAVE_OPLINE();
+ value = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
+ switch (opline->extended_value) {
+ case IS_NULL:
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_ARRAY:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == opline->extended_value);
+ break;
+ case _IS_BOOL:
+ ZVAL_BOOL(EX_VAR(opline->result.var), Z_TYPE_P(value) == IS_TRUE || Z_TYPE_P(value) == IS_FALSE);
+ break;
+ case IS_OBJECT:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ if (Z_OBJ_HT_P(value)->get_class_entry == NULL) {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(value);
+ if (ce->name->len == sizeof("__PHP_Incomplete_Class") - 1
+ && !strncmp(ce->name->val, "__PHP_Incomplete_Class", ce->name->len)) {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ } else {
+ ZVAL_TRUE(EX_VAR(opline->result.var));
+ }
+ }
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ break;
+ case IS_RESOURCE:
+ if (Z_TYPE_P(value) == opline->extended_value) {
+ const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(value) TSRMLS_CC);
+ ZVAL_BOOL(EX_VAR(opline->result.var), type_name != NULL);
+ } else {
+ ZVAL_FALSE(EX_VAR(opline->result.var));
+ }
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_FASTCALL ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -43821,31 +44025,31 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CONST_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CONST_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CONST_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CONST_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CONST_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_TMP_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_TMP_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_TMP_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_TMP_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_TMP_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_VAR_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_VAR_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_VAR_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_VAR_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CV_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CV_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CV_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CV_HANDLER,
+ ZEND_TYPE_CHECK_SPEC_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c
index 7ae371e..f99a34a 100644
--- a/Zend/zend_vm_opcodes.c
+++ b/Zend/zend_vm_opcodes.c
@@ -145,7 +145,7 @@ const char *zend_vm_opcodes_map[169] = {
"ZEND_SEND_USER",
"ZEND_STRLEN",
NULL,
- NULL,
+ "ZEND_TYPE_CHECK",
NULL,
NULL,
NULL,
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 1c20fc6..c4be566 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -145,6 +145,7 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);
#define ZEND_SEND_ARRAY 119
#define ZEND_SEND_USER 120
#define ZEND_STRLEN 121
+#define ZEND_TYPE_CHECK 123
#define ZEND_PRE_INC_OBJ 132
#define ZEND_PRE_DEC_OBJ 133
#define ZEND_POST_INC_OBJ 134
Copy link

ghost commented Jul 14, 2014

缩进不是4个空格吗?不能忍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment