]> granicus.if.org Git - php/commitdiff
Implemented builtin instruction for type check functions - is_*()
authorDmitry Stogov <dmitry@zend.com>
Mon, 14 Jul 2014 06:33:11 +0000 (10:33 +0400)
committerDmitry Stogov <dmitry@zend.com>
Mon, 14 Jul 2014 06:33:11 +0000 (10:33 +0400)
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h

index 56d0d979cd3f8940aff99d8bf28dc041c405ad51..90d36b19dcb44237917480ff3838459ea9ab62f4 100644 (file)
@@ -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;
+                                               }
+                                       }
                                }
                        }
                }
index dfe6651f3b8ab3ac41dcfc8b28dd804d7ae5abaa..93c6795fb92b527bd76288cd35ed625f02f8ee8c 100644 (file)
@@ -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)
index ecd15ffe9ae9fb828da7146b7330b6a9ed86c1c7..dab0fc5e5e587756168edfe9d9bfd1878483d787 100644 (file)
@@ -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,
index 7ae371e068e17c47de02b2c8475e28c6bf3215d7..f99a34a0216d5dbd18bac17362a16f5594ab4993 100644 (file)
@@ -145,7 +145,7 @@ const char *zend_vm_opcodes_map[169] = {
        "ZEND_SEND_USER",
        "ZEND_STRLEN",
        NULL,
-       NULL,
+       "ZEND_TYPE_CHECK",
        NULL,
        NULL,
        NULL,
index 1c20fc6228b956a472d6866d623699a5e132c264..c4be566726d136dc7f03af2420ed3b3cceff5865 100644 (file)
@@ -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