]> granicus.if.org Git - php/commitdiff
Implemented Request #76178 (Class constants are slow: they should be inlined at runtime)
authorDmitry Stogov <dmitry@zend.com>
Thu, 3 May 2018 11:40:18 +0000 (14:40 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 3 May 2018 11:40:18 +0000 (14:40 +0300)
Run-time cache is used to eliminate recalculation of constant expression in RECV_INIT opcode (only non reference countable values are cached).

Zend/zend_opcode.c
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/compact_literals.c

index f5348083213240cec8c99a3f9e5fd703c5075ba3..869baae0205da50bed8baa8a1cc1bc11165e1413 100644 (file)
@@ -579,6 +579,16 @@ ZEND_API int pass_two(zend_op_array *op_array)
        end = opline + op_array->last;
        while (opline < end) {
                switch (opline->opcode) {
+                       case ZEND_RECV_INIT:
+                               {
+                                       zval *val = CT_CONSTANT(opline->op2);
+                                       if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+                                               uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
+                                               Z_CACHE_SLOT_P(val) = slot;
+                                               op_array->cache_size += sizeof(zval);
+                                       }
+                               }
+                               break;
                        case ZEND_FAST_CALL:
                                opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
                                ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
index b0a1ce589d3b2bf702376ffe63c29a3adf01a5aa..a57f5ae8fe09afa2ae9668d8c5d5e6e43864962e 100644 (file)
@@ -192,6 +192,7 @@ struct _zval_struct {
        } u1;
        union {
                uint32_t     next;                 /* hash collision chain */
+               uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
                uint32_t     opline_num;           /* opline number (for FAST_CALL) */
                uint32_t     lineno;               /* line number (for ast nodes) */
                uint32_t     num_args;             /* arguments number for EX(This) */
@@ -404,6 +405,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_NEXT(zval)                           (zval).u2.next
 #define Z_NEXT_P(zval_p)                       Z_NEXT(*(zval_p))
 
+#define Z_CACHE_SLOT(zval)                     (zval).u2.cache_slot
+#define Z_CACHE_SLOT_P(zval_p)         Z_CACHE_SLOT(*(zval_p))
+
 #define Z_LINENO(zval)                         (zval).u2.lineno
 #define Z_LINENO_P(zval_p)                     Z_LINENO(*(zval_p))
 
index cad1ca2ebc3bf8c618a61f93c3a386498e4b7761..d756e97bc9ccab282c853828754c770921152d2e 100644 (file)
@@ -4724,14 +4724,28 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT)
        arg_num = opline->op1.num;
        param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
        if (arg_num > EX_NUM_ARGS()) {
-               ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
-               if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
-                       SAVE_OPLINE();
-                       if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
-                               zval_ptr_dtor_nogc(param);
-                               ZVAL_UNDEF(param);
-                               HANDLE_EXCEPTION();
+               zval *default_value = RT_CONSTANT(opline, opline->op2);
+
+               if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
+                       zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
+
+                       /* we keep in cache only not refcounted values */
+                       if (Z_TYPE_P(cache_val) != IS_UNDEF) {
+                               ZVAL_COPY_VALUE(param, cache_val);
+                       } else {
+                               SAVE_OPLINE();
+                               ZVAL_COPY(param, default_value);
+                               if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
+                                       zval_ptr_dtor_nogc(param);
+                                       ZVAL_UNDEF(param);
+                                       HANDLE_EXCEPTION();
+                               }
+                               if (!Z_REFCOUNTED_P(param)) {
+                                       ZVAL_COPY_VALUE(cache_val, param);
+                               }
                        }
+               } else {
+                       ZVAL_COPY(param, default_value);
                }
        }
 
index 2fbbf0fb21dbef3068d1a60b42696d8004f34441..c72ebebc72dbdc4add9c0e03b4cb665813e51f86 100644 (file)
@@ -2237,14 +2237,28 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON
        arg_num = opline->op1.num;
        param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
        if (arg_num > EX_NUM_ARGS()) {
-               ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
-               if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
-                       SAVE_OPLINE();
-                       if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
-                               zval_ptr_dtor_nogc(param);
-                               ZVAL_UNDEF(param);
-                               HANDLE_EXCEPTION();
+               zval *default_value = RT_CONSTANT(opline, opline->op2);
+
+               if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
+                       zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
+
+                       /* we keep in cache only not refcounted values */
+                       if (Z_TYPE_P(cache_val) != IS_UNDEF) {
+                               ZVAL_COPY_VALUE(param, cache_val);
+                       } else {
+                               SAVE_OPLINE();
+                               ZVAL_COPY(param, default_value);
+                               if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
+                                       zval_ptr_dtor_nogc(param);
+                                       ZVAL_UNDEF(param);
+                                       HANDLE_EXCEPTION();
+                               }
+                               if (!Z_REFCOUNTED_P(param)) {
+                                       ZVAL_COPY_VALUE(cache_val, param);
+                               }
                        }
+               } else {
+                       ZVAL_COPY(param, default_value);
                }
        }
 
index b74df321f13b9084b1f7af006301e422e06d3cbb..9d83791840e28347a3372ecd4c6d077c150b9065 100644 (file)
@@ -740,6 +740,25 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                zend_hash_destroy(&hash);
                zend_arena_release(&ctx->arena, checkpoint);
 
+               if (1) {
+                       opline = op_array->opcodes;
+                       while (1) {
+                               if (opline->opcode == ZEND_RECV_INIT) {
+                                       zval *val = &op_array->literals[opline->op2.constant];
+
+                                       if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+                                               uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
+
+                                               Z_CACHE_SLOT_P(val) = slot;
+                                               op_array->cache_size += sizeof(zval);
+                                       }
+                               } else if (opline->opcode != ZEND_RECV) {
+                                       break;
+                               }
+                               opline++;
+                       }
+               }
+
 #if DEBUG_COMPACT_LITERALS
                {
                        int i, use_copy;