]> granicus.if.org Git - php/commitdiff
Use run-time cache to avoid repeatable hash lookups in ZEND_DECLARE_CLASS_DELAYED
authorDmitry Stogov <dmitry@zend.com>
Fri, 19 Jul 2019 08:46:03 +0000 (11:46 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 19 Jul 2019 08:46:03 +0000 (11:46 +0300)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/compact_literals.c

index 07a987aeef4de434abf97ad54a124557f390555f..7570e39dfe6fb7584ac4deaa86e8d82b5c4af3ac 100644 (file)
@@ -1140,11 +1140,24 @@ ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_
 }
 /* }}} */
 
-ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */
+ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */
 {
        if (first_early_binding_opline != (uint32_t)-1) {
                zend_bool orig_in_compilation = CG(in_compilation);
                uint32_t opline_num = first_early_binding_opline;
+               void **run_time_cache;
+
+               if (!ZEND_MAP_PTR(op_array->run_time_cache)) {
+                       void *ptr;
+
+                       ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE);
+                       ptr = emalloc(op_array->cache_size + sizeof(void*));
+                       ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr);
+                       ptr = (char*)ptr + sizeof(void*);
+                       ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr);
+                       memset(ptr, 0, op_array->cache_size);
+               }
+               run_time_cache = RUN_TIME_CACHE(op_array);
 
                CG(in_compilation) = 1;
                while (opline_num != (uint32_t)-1) {
@@ -1158,7 +1171,10 @@ ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint3
                                zend_class_entry *parent_ce = zend_hash_find_ex_ptr(EG(class_table), lc_parent_name, 1);
 
                                if (parent_ce) {
-                                       zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv);
+                                       if (zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv)) {
+                                               /* Store in run-time cache */
+                                               ((void**)((char*)run_time_cache + opline->extended_value))[0] = ce;
+                                       }
                                }
                        }
                        opline_num = op_array->opcodes[opline_num].result.opline_num;
@@ -6501,6 +6517,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
                ) {
                        CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING;
                        opline->opcode = ZEND_DECLARE_CLASS_DELAYED;
+                       opline->extended_value = zend_alloc_cache_slot();
                        opline->result_type = IS_UNUSED;
                        opline->result.opline_num = -1;
                }
index 2d7c18fc584e227da73e499c216d90fa283cd00f..a3dd2b2272629de7b89bad8a678e0a83fe56ef36 100644 (file)
@@ -753,7 +753,7 @@ void zend_do_free(znode *op1);
 ZEND_API int do_bind_function(zval *lcname);
 ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name);
 ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array);
-ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline);
+ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline);
 
 void zend_do_extended_info(void);
 void zend_do_extended_fcall_begin(void);
index 327e6c17e1299a72bc5aae833495c13dc442624d..ebff7e9593e1efc5242225b5bf86710930ad5a0e 100644 (file)
@@ -7247,21 +7247,28 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
 {
        USE_OPLINE
        zval *lcname, *zv;
+       zend_class_entry *ce;
 
-       SAVE_OPLINE();
-       lcname = RT_CONSTANT(opline, opline->op1);
-       zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1);
-
-       if (zv) {
-               zend_class_entry *ce = Z_CE_P(zv);
-               zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
-               if (UNEXPECTED(!zv)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
-               } else {
-                       zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+       ce = CACHED_PTR(opline->extended_value);
+       if (ce == NULL) {
+               lcname = RT_CONSTANT(opline, opline->op1);
+               zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1);
+               if (zv) {
+                       SAVE_OPLINE();
+                       ce = Z_CE_P(zv);
+                       zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
+                       if (UNEXPECTED(!zv)) {
+                               zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+                       } else {
+                               zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+                               if (UNEXPECTED(EG(exception))) {
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
                }
+               CACHE_PTR(opline->extended_value, ce);
        }
-       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
 }
 
 ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
index b93a21a9feee839d7224f4f41a6200073789c46c..00ed5084924bd1ca9ce9bf32f667eaaf5fc47da9 100644 (file)
@@ -6347,21 +6347,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_DELAYED_SPEC_CON
 {
        USE_OPLINE
        zval *lcname, *zv;
+       zend_class_entry *ce;
 
-       SAVE_OPLINE();
-       lcname = RT_CONSTANT(opline, opline->op1);
-       zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1);
-
-       if (zv) {
-               zend_class_entry *ce = Z_CE_P(zv);
-               zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
-               if (UNEXPECTED(!zv)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
-               } else {
-                       zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+       ce = CACHED_PTR(opline->extended_value);
+       if (ce == NULL) {
+               lcname = RT_CONSTANT(opline, opline->op1);
+               zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1);
+               if (zv) {
+                       SAVE_OPLINE();
+                       ce = Z_CE_P(zv);
+                       zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
+                       if (UNEXPECTED(!zv)) {
+                               zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+                       } else {
+                               zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+                               if (UNEXPECTED(EG(exception))) {
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
                }
+               CACHE_PTR(opline->extended_value, ce);
        }
-       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
index b636fbf5ba9c5889848d56e816027a13546f8bd0..f754dbaa448eb42b1527c50741481cd70143486d 100644 (file)
@@ -772,6 +772,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                                        break;
                                case ZEND_DECLARE_LAMBDA_FUNCTION:
                                case ZEND_DECLARE_ANON_CLASS:
+                               case ZEND_DECLARE_CLASS_DELAYED:
                                        opline->extended_value = cache_size;
                                        cache_size += sizeof(void *);
                                        break;