]> granicus.if.org Git - php/commitdiff
Use run-time cache to avoid repeatable hash lookups when creating anonymous functions...
authorDmitry Stogov <dmitry@zend.com>
Fri, 19 Jul 2019 07:43:49 +0000 (10:43 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 19 Jul 2019 07:43:49 +0000 (10:43 +0300)
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
ext/opcache/Optimizer/compact_literals.c

index d8180c9bee5c92570c98127615dc8ec82b1fe49e..59dea8664b4f362e93d4af7d143145ec08f97822 100644 (file)
@@ -5851,6 +5851,7 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
 
        if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
                opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
+               opline->extended_value = zend_alloc_cache_slot();
                opline->op1_type = IS_CONST;
                LITERAL_STR(opline->op1, key);
        } else {
@@ -6470,6 +6471,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
 
        if (decl->flags & ZEND_ACC_ANON_CLASS) {
                opline->opcode = ZEND_DECLARE_ANON_CLASS;
+               opline->extended_value = zend_alloc_cache_slot();
                opline->result_type = IS_VAR;
                opline->result.var = get_temporary_variable();
 
index 0224e674e77e6add9fa80208a4dc0322b292a59b..327e6c17e1299a72bc5aae833495c13dc442624d 100644 (file)
@@ -7264,24 +7264,28 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
-ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY)
+ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
 {
        zval *zv;
        zend_class_entry *ce;
        USE_OPLINE
 
-       zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
-       ZEND_ASSERT(zv != NULL);
-       ce = Z_CE_P(zv);
-       Z_CE_P(EX_VAR(opline->result.var)) = ce;
-
-       if (ce->ce_flags & ZEND_ACC_LINKED) {
-               ZEND_VM_NEXT_OPCODE();
-       } else {
-               SAVE_OPLINE();
-               zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
-               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+       ce = CACHED_PTR(opline->extended_value);
+       if (UNEXPECTED(ce == NULL)) {
+               zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
+               ZEND_ASSERT(zv != NULL);
+               ce = Z_CE_P(zv);
+               if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
+                       SAVE_OPLINE();
+                       zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
+               }
+               CACHE_PTR(opline->extended_value, ce);
        }
+       Z_CE_P(EX_VAR(opline->result.var)) = ce;
+       ZEND_VM_NEXT_OPCODE();
 }
 
 ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY)
@@ -7550,19 +7554,26 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
-ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
+ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT)
 {
        USE_OPLINE
+       zend_function *func;
        zval *zfunc;
        zval *object;
        zend_class_entry *called_scope;
 
-       zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
-       ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION);
+       func = CACHED_PTR(opline->extended_value);
+       if (UNEXPECTED(func == NULL)) {
+               zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
+               ZEND_ASSERT(zfunc != NULL);
+               func = Z_FUNC_P(zfunc);
+               ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
+               CACHE_PTR(opline->extended_value, func);
+       }
 
        if (Z_TYPE(EX(This)) == IS_OBJECT) {
                called_scope = Z_OBJCE(EX(This));
-               if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
+               if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
                                (EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
                        object = NULL;
                } else {
@@ -7572,7 +7583,7 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
                called_scope = Z_CE(EX(This));
                object = NULL;
        }
-       zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
+       zend_create_closure(EX_VAR(opline->result.var), func,
                EX(func)->op_array.scope, called_scope, object);
 
        ZEND_VM_NEXT_OPCODE();
index 2c21ea0a04b6971b9066d27b9ecdcd5a11bf122d..b93a21a9feee839d7224f4f41a6200073789c46c 100644 (file)
@@ -2430,18 +2430,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
        zend_class_entry *ce;
        USE_OPLINE
 
-       zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
-       ZEND_ASSERT(zv != NULL);
-       ce = Z_CE_P(zv);
-       Z_CE_P(EX_VAR(opline->result.var)) = ce;
-
-       if (ce->ce_flags & ZEND_ACC_LINKED) {
-               ZEND_VM_NEXT_OPCODE();
-       } else {
-               SAVE_OPLINE();
-               zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
-               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+       ce = CACHED_PTR(opline->extended_value);
+       if (UNEXPECTED(ce == NULL)) {
+               zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
+               ZEND_ASSERT(zv != NULL);
+               ce = Z_CE_P(zv);
+               if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
+                       SAVE_OPLINE();
+                       zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
+               }
+               CACHE_PTR(opline->extended_value, ce);
        }
+       Z_CE_P(EX_VAR(opline->result.var)) = ce;
+       ZEND_VM_NEXT_OPCODE();
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -9395,16 +9399,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_U
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
+       zend_function *func;
        zval *zfunc;
        zval *object;
        zend_class_entry *called_scope;
 
-       zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
-       ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION);
+       func = CACHED_PTR(opline->extended_value);
+       if (UNEXPECTED(func == NULL)) {
+               zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
+               ZEND_ASSERT(zfunc != NULL);
+               func = Z_FUNC_P(zfunc);
+               ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
+               CACHE_PTR(opline->extended_value, func);
+       }
 
        if (Z_TYPE(EX(This)) == IS_OBJECT) {
                called_scope = Z_OBJCE(EX(This));
-               if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
+               if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
                                (EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
                        object = NULL;
                } else {
@@ -9414,7 +9425,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C
                called_scope = Z_CE(EX(This));
                object = NULL;
        }
-       zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
+       zend_create_closure(EX_VAR(opline->result.var), func,
                EX(func)->op_array.scope, called_scope, object);
 
        ZEND_VM_NEXT_OPCODE();
index 6ef58e4d906ce8b0e563854fa0ccd884a682a076..7ae64a3224fad181de524af7bbca4120e3aac883 100644 (file)
@@ -363,11 +363,11 @@ static uint32_t zend_vm_opcodes_flags[195] = {
        0x00000000,
        0x00000101,
        0x00000000,
-       0x00000103,
+       0x00040103,
        0x00000303,
        0x00000003,
        0x00000303,
-       0x00000000,
+       0x00040000,
        0x00000000,
        0x00060757,
        0x00000000,
index 0078600b524487137061ea4ab62030a7038af467..b636fbf5ba9c5889848d56e816027a13546f8bd0 100644 (file)
@@ -770,6 +770,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                                                bind_var_slot[opline->op2.constant] = opline->extended_value;
                                        }
                                        break;
+                               case ZEND_DECLARE_LAMBDA_FUNCTION:
+                               case ZEND_DECLARE_ANON_CLASS:
+                                       opline->extended_value = cache_size;
+                                       cache_size += sizeof(void *);
+                                       break;
                        }
                        opline++;
                }