]> granicus.if.org Git - php/commitdiff
Improved class type hints checks, by caching resolved class entries in run-time cache.
authorDmitry Stogov <dmitry@zend.com>
Wed, 17 Jun 2015 09:07:43 +0000 (12:07 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 17 Jun 2015 09:07:43 +0000 (12:07 +0300)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/compact_literals.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c

index 0eecbf6810c0e1b0f9f8473a5f989fe772e95cc3..5045d4c85d5bc84f63298966d645a87c6c3d1439 100644 (file)
@@ -2032,7 +2032,6 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
 }
 /* }}} */
 
-
 static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */
 {
        if (return_info->type_hint != IS_UNDEF) {
@@ -2041,11 +2040,16 @@ static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info)
                        opline->result_type = expr->op_type = IS_TMP_VAR;
                        opline->result.var = expr->u.op.var = get_temporary_variable(CG(active_op_array));
                }
+               if (return_info->class_name) {
+                       opline->op2.num = CG(active_op_array)->cache_size;
+                       CG(active_op_array)->cache_size += sizeof(void*);
+               } else {
+                       opline->op2.num = -1;
+               }
        }
 }
 /* }}} */
 
-
 void zend_emit_final_return(zval *zv) /* {{{ */
 {
        znode zn;
@@ -4222,7 +4226,6 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */
 }
 /* }}} */
 
-
 static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{ */
 {
        if (ast->kind == ZEND_AST_TYPE) {
@@ -4238,11 +4241,9 @@ static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{
                        if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
                                class_name = zend_resolve_class_name_ast(ast);
                                zend_assert_valid_class_name(class_name);
-                               arg_info->lower_class_name = zend_string_tolower(class_name);
                        } else {
                                zend_ensure_valid_class_fetch_type(fetch_type);
                                zend_string_addref(class_name);
-                               arg_info->lower_class_name = NULL;
                        }
 
                        arg_info->type_hint = IS_OBJECT;
@@ -4252,7 +4253,6 @@ static void zend_compile_typename(zend_ast *ast, zend_arg_info *arg_info) /* {{{
 }
 /* }}} */
 
-
 void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
 {
        zend_ast_list *list = zend_ast_get_list(ast);
@@ -4390,6 +4390,22 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
                                        }
                                }
                        }
+
+                       /* Allocate cache slot to speed-up run-time class resolution */
+                       if (opline->opcode == ZEND_RECV_INIT) {
+                               if (arg_info->class_name) {
+                                       zend_alloc_cache_slot(opline->op2.constant);
+                               } else {
+                                       Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1;
+                               }
+                       } else {
+                               if (arg_info->class_name) {
+                                       opline->op2.num = op_array->cache_size;
+                                       op_array->cache_size += sizeof(void*);
+                               } else {
+                                       opline->op2.num = -1;
+                               }
+                       }
                }
        }
 
index 1ed6e236b0205fd7115e2bf91118a210f4315970..106d0fc475d6cd5531f7b8b67f420a293fd76c20 100644 (file)
@@ -300,7 +300,6 @@ typedef struct _zend_internal_arg_info {
        zend_uchar pass_by_reference;
        zend_bool allow_null;
        zend_bool is_variadic;
-       void *reserved; /* to align with zend_arg_info */
 } zend_internal_arg_info;
 
 /* arg_info for user functions */
@@ -311,7 +310,6 @@ typedef struct _zend_arg_info {
        zend_uchar pass_by_reference;
        zend_bool allow_null;
        zend_bool is_variadic;
-       zend_string *lower_class_name;
 } zend_arg_info;
 
 /* the following structure repeats the layout of zend_internal_arg_info,
index e63fc2dd321b67845a8ef5e907cb023f900f29e1..9190eff2c346b4d606bba57504486ed82b4b6052 100644 (file)
@@ -585,21 +585,9 @@ ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info
        }
 }
 
-ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce)
+static zend_always_inline zend_class_entry* zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info)
 {
-       /* optimization to not always recalculate the lowercase name and hash */
-       if (cur_arg_info->lower_class_name) {
-               *pce = zend_hash_find_ptr(EG(class_table), cur_arg_info->lower_class_name);
-       } else { /* "extra" fetch type */
-               *pce = zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
-       }
-
-       *class_name = (*pce) ? (*pce)->name->val : cur_arg_info->class_name->val;
-       if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
-               return "implement interface ";
-       } else {
-               return "be an instance of ";
-       }
+       return zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
 }
 
 ZEND_API void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
@@ -749,15 +737,15 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
        }
 }
 
-static int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value)
+static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
 {
        zend_arg_info *cur_arg_info;
-       char *need_msg, *class_name;
+       char *need_msg;
        zend_class_entry *ce;
 
        if (EXPECTED(arg_num <= zf->common.num_args)) {
                cur_arg_info = &zf->common.arg_info[arg_num-1];
-       } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
+       } else if (UNEXPECTED(zf->common.fn_flags & ZEND_ACC_VARIADIC)) {
                cur_arg_info = &zf->common.arg_info[zf->common.num_args];
        } else {
                return 1;
@@ -767,16 +755,40 @@ static int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
                ZVAL_DEREF(arg);
                if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
                        if (cur_arg_info->class_name) {
-                               need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-                               if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
-                                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                               if (EXPECTED(*cache_slot)) {
+                                       ce = (zend_class_entry*)*cache_slot;
+                               } else {
+                                       ce = zend_verify_arg_class_kind(cur_arg_info);
+                                       if (UNEXPECTED(!ce)) {
+                                               zend_verify_arg_error(zf, arg_num, "be an instance of ", cur_arg_info->class_name->val, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                                               return 0;
+                                       }
+                                       *cache_slot = (void*)ce;
+                               }
+                               if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(arg), ce))) {
+                                       need_msg =
+                                               (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                                               "implement interface " : "be an instance of ";
+                                       zend_verify_arg_error(zf, arg_num, need_msg, ce->name->val, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
                                        return 0;
                                }
                        }
                } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
                        if (cur_arg_info->class_name) {
-                               need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-                               zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
+                               if (EXPECTED(*cache_slot)) {
+                                       ce = (zend_class_entry*)*cache_slot;
+                               } else {
+                                       ce = zend_verify_arg_class_kind(cur_arg_info);
+                                       if (UNEXPECTED(!ce)) {
+                                               zend_verify_arg_error(zf, arg_num, "be an instance of ", cur_arg_info->class_name->val, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                                               return 0;
+                                       }
+                                       *cache_slot = (void*)ce;
+                               }
+                               need_msg =
+                                       (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                                       "implement interface " : "be an instance of ";
+                               zend_verify_arg_error(zf, arg_num, need_msg, ce->name->val, zend_zval_type_name(arg), "", arg);
                                return 0;
                        } else if (cur_arg_info->type_hint == IS_CALLABLE) {
                                if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
@@ -795,7 +807,7 @@ static int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
        return 1;
 }
 
-static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num)
+static zend_always_inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num, void **cache_slot)
 {
        zend_arg_info *cur_arg_info;
        char *need_msg;
@@ -803,7 +815,7 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
 
        if (EXPECTED(arg_num <= zf->common.num_args)) {
                cur_arg_info = &zf->common.arg_info[arg_num-1];
-       } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
+       } else if (UNEXPECTED(zf->common.fn_flags & ZEND_ACC_VARIADIC)) {
                cur_arg_info = &zf->common.arg_info[zf->common.num_args];
        } else {
                return 1;
@@ -811,10 +823,20 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
 
        if (cur_arg_info->type_hint) {
                if (cur_arg_info->class_name) {
-                       char *class_name;
-
-                       need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
+                       if (EXPECTED(*cache_slot)) {
+                               ce = (zend_class_entry*)*cache_slot;
+                       } else {
+                               ce = zend_verify_arg_class_kind(cur_arg_info);
+                               if (UNEXPECTED(!ce)) {
+                                       zend_verify_arg_error(zf, arg_num, "be an instance of ", cur_arg_info->class_name->val, "none", "", NULL);
+                                       return 0;
+                               }
+                               *cache_slot = (void*)ce;
+                       }
+                       need_msg =
+                               (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                               "implement interface " : "be an instance of ";
+                       zend_verify_arg_error(zf, arg_num, need_msg, ce->name->val, "none", "", NULL);
                } else if (cur_arg_info->type_hint == IS_CALLABLE) {
                        zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
                } else {
@@ -825,10 +847,10 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
        return 1;
 }
 
-static int zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num)
+static zend_always_inline int zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num, void **cache_slot)
 {
        if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
-           zend_verify_missing_arg_type(EX(func), arg_num)) {
+           zend_verify_missing_arg_type(EX(func), arg_num, cache_slot)) {
                const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : "";
                const char *space = EX(func)->common.scope ? "::" : "";
                const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main";
@@ -926,24 +948,48 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
 }
 #endif
 
-static void zend_verify_return_type(zend_function *zf, zval *ret)
+static zend_always_inline void zend_verify_return_type(zend_function *zf, zval *ret, void **cache_slot)
 {
        zend_arg_info *ret_info = zf->common.arg_info - 1;
-       char *need_msg, *class_name;
+       char *need_msg;
        zend_class_entry *ce;
 
        if (ret_info->type_hint) {
                if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
                        if (ret_info->class_name) {
-                               need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-                               if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
-                                       zend_verify_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
+                               if (EXPECTED(*cache_slot)) {
+                                       ce = (zend_class_entry*)*cache_slot;
+                               } else {
+                                       ce = zend_verify_arg_class_kind(ret_info);
+                                       if (UNEXPECTED(!ce)) {
+                                               zend_verify_return_error(zf, "be an instance of ", ret_info->class_name->val, "instance of ", Z_OBJCE_P(ret)->name->val);
+                                               return;
+                                       }
+                                       *cache_slot = (void*)ce;
+                               }
+                               if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(ret), ce))) {
+                                       need_msg =
+                                               (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                                               "implement interface " : "be an instance of ";
+                                       zend_verify_return_error(zf, need_msg, ce->name->val, "instance of ", Z_OBJCE_P(ret)->name->val);
                                }
                        }
                } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
                        if (ret_info->class_name) {
-                               need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-                               zend_verify_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
+                               if (EXPECTED(*cache_slot)) {
+                                       ce = (zend_class_entry*)*cache_slot;
+                               } else {
+                                       ce = zend_verify_arg_class_kind(ret_info);
+                                       if (UNEXPECTED(!ce)) {
+                                               zend_verify_return_error(zf, "be an instance of ", ret_info->class_name->val, zend_zval_type_name(ret), "");
+                                               return;
+                                       }
+                                       *cache_slot = (void*)ce;
+                               }
+                               need_msg =
+                                       (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                                       "implement interface " : "be an instance of ";
+                               zend_verify_return_error(zf, need_msg, ce->name->val, zend_zval_type_name(ret), "");
                        } else if (ret_info->type_hint == IS_CALLABLE) {
                                if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) {
                                        zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
@@ -958,7 +1004,7 @@ static void zend_verify_return_type(zend_function *zf, zval *ret)
        }
 }
 
-static inline int zend_verify_missing_return_type(zend_function *zf)
+static zend_always_inline int zend_verify_missing_return_type(zend_function *zf, void **cache_slot)
 {
        zend_arg_info *ret_info = zf->common.arg_info - 1;
        char *need_msg;
@@ -966,10 +1012,20 @@ static inline int zend_verify_missing_return_type(zend_function *zf)
 
        if (ret_info->type_hint) {
                if (ret_info->class_name) {
-                       char *class_name;
-
-                       need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-                       zend_verify_return_error(zf, need_msg, class_name, "none", "");
+                       if (EXPECTED(*cache_slot)) {
+                               ce = (zend_class_entry*)*cache_slot;
+                       } else {
+                               ce = zend_verify_arg_class_kind(ret_info);
+                               if (UNEXPECTED(!ce)) {
+                                       zend_verify_return_error(zf, "be an instance of ", ret_info->class_name->val, "none", "");
+                                       return 0;
+                               }
+                               *cache_slot = (void*)ce;
+                       }
+                       need_msg =
+                               (ce->ce_flags & ZEND_ACC_INTERFACE) ?
+                               "implement interface " : "be an instance of ";
+                       zend_verify_return_error(zf, need_msg, ce->name->val, "none", "");
                        return 0;
                } else if (ret_info->type_hint == IS_CALLABLE) {
                        zend_verify_return_error(zf, "be callable", "", "none", "");
index 75d61ded53170bdcfe2082b4beee3d9dd056e2fa..8430fc8499a1506ac97b073ce21c0a3f805c07c8 100644 (file)
@@ -50,7 +50,6 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name,
 ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions);
 
 ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce);
-ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce);
 ZEND_API void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg);
 ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind);
 ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind);
index abb91b1ee3e778b751f1258e2ae0bf6022afc589..1c760c5902ec346ea7cb79102f59787d2c799fb4 100644 (file)
@@ -410,10 +410,6 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
                        }
                        if (arg_info[i].class_name) {
                                zend_string_release(arg_info[i].class_name);
-
-                               if (arg_info[i].lower_class_name) {
-                                       zend_string_release(arg_info[i].lower_class_name);
-                               }
                        }
                }
                efree(arg_info);
index 0fe820a20fa62a114ce60c729c4ce1536d9f9b43..686eb2a2931c4560cb6dbd22307086cbbeb8b637 100644 (file)
@@ -3919,13 +3919,11 @@ ZEND_VM_C_LABEL(fcall_end):
 
 ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
 {
-#if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (OP1_TYPE == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED)
@@ -3959,7 +3957,7 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
                        FREE_OP1();
@@ -4752,14 +4750,14 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
 
        if (UNEXPECTED(arg_num > EX_NUM_ARGS())) {
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num))) {
+               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num, CACHE_ADDR(opline->op2.num)))) {
                        HANDLE_EXCEPTION();
                }
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL))) {
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) {
                        HANDLE_EXCEPTION();
                }
        }
@@ -4794,8 +4792,10 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
+               zval *default_value = EX_CONSTANT(opline->op2);
+
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)))) {
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))))) {
                        HANDLE_EXCEPTION();
                }
        }
@@ -4824,7 +4824,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY)
                        param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
                        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                                do {
-                                       zend_verify_arg_type(EX(func), arg_num, param, NULL);
+                                       zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num));
                                        if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
                                        ZEND_HASH_FILL_ADD(param);
                                        param++;
index c7fef27bd4da51c55efbafabe996d19a2dd5716b..9d7fac449b699e65a3ba22078cd9e2ac0ee85af8 100644 (file)
@@ -1202,14 +1202,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_
 
        if (UNEXPECTED(arg_num > EX_NUM_ARGS())) {
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num))) {
+               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num, CACHE_ADDR(opline->op2.num)))) {
                        HANDLE_EXCEPTION();
                }
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL))) {
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) {
                        HANDLE_EXCEPTION();
                }
        }
@@ -1237,7 +1237,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEN
                        param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
                        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                                do {
-                                       zend_verify_arg_type(EX(func), arg_num, param, NULL);
+                                       zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num));
                                        if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
                                        ZEND_HASH_FILL_ADD(param);
                                        param++;
@@ -2354,8 +2354,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
+               zval *default_value = EX_CONSTANT(opline->op2);
+
                SAVE_OPLINE();
-               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)))) {
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))))) {
                        HANDLE_EXCEPTION();
                }
        }
@@ -7973,13 +7975,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-#if 0 || (IS_CONST != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (IS_CONST == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if 0 || (IS_CONST != IS_UNUSED)
@@ -8013,7 +8013,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
 
@@ -13854,13 +13854,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UN
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-#if 0 || (IS_TMP_VAR != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (IS_TMP_VAR == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if 0 || (IS_TMP_VAR != IS_UNUSED)
@@ -13894,7 +13892,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
                        zval_ptr_dtor_nogc(free_op1);
@@ -19605,13 +19603,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-#if 0 || (IS_VAR != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (IS_VAR == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if 0 || (IS_VAR != IS_UNUSED)
@@ -19645,7 +19641,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
                        zval_ptr_dtor_nogc(free_op1);
@@ -25379,13 +25375,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_UNUS
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-#if 0 || (IS_UNUSED != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (IS_UNUSED == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if 0 || (IS_UNUSED != IS_UNUSED)
@@ -25419,7 +25413,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
 
@@ -35013,13 +35007,11 @@ assign_dim_clean:
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-#if 0 || (IS_CV != IS_UNUSED)
        USE_OPLINE
-#endif
 
        SAVE_OPLINE();
        if (IS_CV == IS_UNUSED) {
-               zend_verify_missing_return_type(EX(func));
+               zend_verify_missing_return_type(EX(func), CACHE_ADDR(opline->op2.num));
        } else {
 /* prevents "undefined variable opline" errors */
 #if 0 || (IS_CV != IS_UNUSED)
@@ -35053,7 +35045,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
                                SEPARATE_ZVAL_NOREF(retval_ptr);
                        }
                }
-               zend_verify_return_type(EX(func), retval_ptr);
+               zend_verify_return_type(EX(func), retval_ptr, CACHE_ADDR(opline->op2.num));
 
                if (UNEXPECTED(EG(exception) != NULL)) {
 
index c72e8f6772548cefa5c2fe45096b537bc7913ba1..c20ddbd18356d99c1b006c2647217cd749a30bfa 100644 (file)
@@ -128,6 +128,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
        void *checkpoint = zend_arena_checkpoint(ctx->arena);
 
        if (op_array->last_literal) {
+               cache_size = 0;
                info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
 
            /* Mark literals of specific types */
@@ -286,6 +287,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                                case ZEND_BIND_GLOBAL:
                                        LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1);
                                        break;
+                               case ZEND_RECV_INIT:
+                                       LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 0, 0, 1);
+                                       if (Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) != -1) {
+                                               Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = cache_size;
+                                               cache_size += sizeof(void *);
+                                       }
+                                       break;
+                               case ZEND_RECV:
+                               case ZEND_VERIFY_RETURN_TYPE:
+                                       if (opline->op2.num != -1) {
+                                               opline->op2.num = cache_size;
+                                               cache_size += sizeof(void *);
+                                       }
                                default:
                                        if (ZEND_OP1_TYPE(opline) == IS_CONST) {
                                                LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
@@ -319,7 +333,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
 #endif
 
                /* Merge equal constants */
-               j = 0; cache_size = 0;
+               j = 0;
                zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
                map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
                memset(map, 0, op_array->last_literal * sizeof(int));
@@ -331,15 +345,24 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                        }
                        switch (Z_TYPE(op_array->literals[i])) {
                                case IS_NULL:
-                                       if (l_null < 0) {
-                                               l_null = j;
+                                       if ((info[i].flags & LITERAL_MAY_MERGE)) {
+                                               if (l_null < 0) {
+                                                       l_null = j;
+                                                       if (i != j) {
+                                                               op_array->literals[j] = op_array->literals[i];
+                                                               info[j] = info[i];
+                                                       }
+                                                       j++;
+                                               }
+                                               map[i] = l_null;
+                                       } else {
+                                               map[i] = j;
                                                if (i != j) {
                                                        op_array->literals[j] = op_array->literals[i];
                                                        info[j] = info[i];
                                                }
                                                j++;
                                        }
-                                       map[i] = l_null;
                                        break;
                                case IS_FALSE:
                                        if (l_false < 0) {
index 10a149c9f68ecda4bd164fad6bd61aba81148548..219bb508208ea8b0a6c5de6bc3c79652de8b3171 100644 (file)
@@ -438,9 +438,6 @@ static void zend_file_cache_serialize_op_array(zend_op_array            *op_arra
                                if (!IS_SERIALIZED(p->class_name)) {
                                        SERIALIZE_STR(p->class_name);
                                }
-                               if (p->class_name && !IS_SERIALIZED(p->lower_class_name)) {
-                                       SERIALIZE_STR(p->lower_class_name);
-                               }
                                p++;
                        }
                }
@@ -965,9 +962,6 @@ static void zend_file_cache_unserialize_op_array(zend_op_array           *op_arr
                                if (!IS_UNSERIALIZED(p->class_name)) {
                                        UNSERIALIZE_STR(p->class_name);
                                }
-                               if (p->class_name && !IS_UNSERIALIZED(p->lower_class_name)) {
-                                       UNSERIALIZE_STR(p->lower_class_name);
-                               }
                                p++;
                        }
                }
index 585c34f46e238ba653c009892ea51b934c16a7ec..09eebe0d02523252ec8c30780893e0a24f47905f 100644 (file)
@@ -581,9 +581,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                                }
                                if (arg_info[i].class_name) {
                                        zend_accel_store_interned_string(arg_info[i].class_name);
-                                       if (arg_info[i].lower_class_name) {
-                                               zend_accel_store_interned_string(arg_info[i].lower_class_name);
-                                       }
                                }
                        }
                }
index d721db2febfbc2a02a34aab36ea3f7c843c03d3f..98412109a5ca0f6fa08803a22148fb00eeeeff98 100644 (file)
@@ -225,9 +225,6 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
                        }
                        if (arg_info[i].class_name) {
                                ADD_INTERNED_STRING(arg_info[i].class_name, 1);
-                               if (arg_info[i].lower_class_name) {
-                                       ADD_INTERNED_STRING(arg_info[i].lower_class_name, 1);
-                               }
                        }
                }
        }