]> granicus.if.org Git - php/commitdiff
Added script level constant replacement
authorDmitry Stogov <dmitry@zend.com>
Thu, 11 Apr 2013 11:18:35 +0000 (15:18 +0400)
committerDmitry Stogov <dmitry@zend.com>
Thu, 11 Apr 2013 11:18:35 +0000 (15:18 +0400)
ext/opcache/Optimizer/pass1_5.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/Optimizer/zend_optimizer.h
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h

index dc9e7319a97bac0fb2aa54a6ae264d12168bbdcc..3a32970650bdc0f78628c101dda70b9b807a5887 100644 (file)
@@ -10,6 +10,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
        int i = 0;
        zend_op *opline = op_array->opcodes;
        zend_op *end = opline + op_array->last;
+       zend_bool collect_constants = (op_array == &script->main_op_array);
 
        while (opline < end) {
                switch (opline->opcode) {
@@ -357,7 +358,9 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                zval c;
 
                                if (!zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) {
-                                       break;
+                                       if (!*constants || !zend_optimizer_get_collected_constant(*constants, &ZEND_OP2_LITERAL(opline), &c)) {
+                                               break;
+                                       }
                                }
                                literal_dtor(&ZEND_OP2_LITERAL(opline));
                                ZEND_OP1_TYPE(opline) = IS_CONST;
@@ -388,6 +391,71 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                }
                        }
                        break;
+               case ZEND_DO_FCALL:
+                       /* define("name", scalar); */
+                       if (collect_constants &&
+                           opline->extended_value == 2 &&
+                           ZEND_OP1_TYPE(opline) == IS_CONST &&
+                           Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
+                           Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("define")-1 &&
+                           zend_binary_strcasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), "define", sizeof("define")-1) == 0 &&
+                           (opline-1)->opcode == ZEND_SEND_VAL &&
+                           ZEND_OP1_TYPE(opline-1) == IS_CONST &&
+                           (Z_TYPE(ZEND_OP1_LITERAL(opline-1)) <= IS_BOOL ||
+                            Z_TYPE(ZEND_OP1_LITERAL(opline-1)) == IS_STRING) &&
+                           (opline-2)->opcode == ZEND_SEND_VAL &&
+                           ZEND_OP1_TYPE(opline-2) == IS_CONST &&
+                           Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) {
+                               zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1));
+                       }
+                       break;
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
+               case ZEND_DECLARE_CONST:
+                       if (collect_constants &&
+                           Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
+                           (Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_BOOL ||
+                            Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING)) {
+                               zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
+                       }
+                       break;
+#endif
+
+               case ZEND_RETURN:
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+               case ZEND_RETURN_BY_REF:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+               case ZEND_GENERATOR_RETURN:
+#endif
+               case ZEND_EXIT:
+               case ZEND_THROW:
+               case ZEND_CATCH:
+               case ZEND_BRK:
+               case ZEND_CONT:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+               case ZEND_GOTO:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+               case ZEND_FAST_CALL:
+               case ZEND_FAST_RET:
+#endif
+               case ZEND_JMP:
+               case ZEND_JMPZNZ:
+               case ZEND_JMPZ:
+               case ZEND_JMPNZ:
+               case ZEND_JMPZ_EX:
+               case ZEND_JMPNZ_EX:
+               case ZEND_FE_RESET:
+               case ZEND_FE_FETCH:
+               case ZEND_NEW:
+#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+               case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+               case ZEND_JMP_SET_VAR:
+#endif
+                       collect_constants = 0;
+                       break;
                }
                opline++;
                i++;
index b574ecc81f2da564781d891101a2d8abbddcfbcf..92f5f4a0541f9f69eaec04eeb60926860b681973 100644 (file)
 #include "zend_API.h"\r
 #include "zend_constants.h"\r
 #include "zend_execute.h"\r
+#include "zend_vm.h"\r
 \r
 #define OPTIMIZATION_LEVEL \\r
        ZCG(accel_directives).optimization_level\r
 \r
+static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)\r
+{\r
+       zval_dtor(zvalue);\r
+}\r
+\r
+static void zend_optimizer_collect_constant(HashTable **constants, zval *name, zval* value)\r
+{\r
+       zval val;\r
+\r
+       if (!*constants) {\r
+               *constants = emalloc(sizeof(HashTable));\r
+               zend_hash_init(*constants, 16, NULL, (void (*)(void *))zend_optimizer_zval_dtor_wrapper, 0);\r
+       }\r
+       val = *value;\r
+       zval_copy_ctor(&val);\r
+       zend_hash_add(*constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val, sizeof(zval), NULL);\r
+}\r
+\r
+static int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)\r
+{\r
+       zval *val;\r
+\r
+       if (zend_hash_find(constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val) == SUCCESS) {\r
+               *value = *val;\r
+               zval_copy_ctor(value);\r
+               return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
 int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC)\r
 {\r
        int i = op_array->last_literal;\r
        op_array->last_literal++;\r
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
-       {\r
-               if (i >= CG(context).literals_size) {\r
-                       CG(context).literals_size += 16; /* FIXME */\r
-                       op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));\r
-               }\r
-       }\r
-#else\r
-       if (i >= op_array->size_literal) {\r
-               op_array->size_literal += 16; /* FIXME */\r
-               op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->size_literal * sizeof(zend_literal));\r
-       }\r
-#endif\r
+       op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->last_literal * sizeof(zend_literal));\r
        op_array->literals[i].constant = *zv;\r
        Z_SET_REFCOUNT(op_array->literals[i].constant, 2);\r
        Z_SET_ISREF(op_array->literals[i].constant);\r
@@ -92,7 +111,9 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
 #include "Optimizer/block_pass.c"\r
 #include "Optimizer/optimize_temp_vars_5.c"\r
 \r
-void zend_optimizer(zend_op_array *op_array TSRMLS_DC)\r
+static void zend_optimize(zend_op_array           *op_array,\r
+                          zend_persistent_script  *script,\r
+                          HashTable              **constants TSRMLS_DC)\r
 {\r
        if (op_array->type == ZEND_EVAL_CODE ||\r
            (op_array->fn_flags & ZEND_ACC_INTERACTIVE)) {\r
@@ -137,3 +158,133 @@ void zend_optimizer(zend_op_array *op_array TSRMLS_DC)
         */\r
 #include "Optimizer/pass10.c"\r
 }\r
+\r
+static void zend_accel_optimize(zend_op_array           *op_array,\r
+                                zend_persistent_script  *script,\r
+                                HashTable              **constants TSRMLS_DC)\r
+{\r
+       zend_op *opline, *end;\r
+\r
+       /* Revert pass_two() */\r
+       opline = op_array->opcodes;\r
+       end = opline + op_array->last;\r
+       while (opline < end) {\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+               if (opline->op1_type == IS_CONST) {\r
+                       opline->op1.constant = opline->op1.literal - op_array->literals;\r
+               }\r
+               if (opline->op2_type == IS_CONST) {\r
+                       opline->op2.constant = opline->op2.literal - op_array->literals;\r
+               }\r
+#endif\r
+               switch (opline->opcode) {\r
+                       case ZEND_JMP:\r
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO\r
+                       case ZEND_GOTO:\r
+#endif\r
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO\r
+                       case ZEND_FAST_CALL:\r
+#endif\r
+                               ZEND_OP1(opline).opline_num = ZEND_OP1(opline).jmp_addr - op_array->opcodes;\r
+                               break;\r
+                       case ZEND_JMPZ:\r
+                       case ZEND_JMPNZ:\r
+                       case ZEND_JMPZ_EX:\r
+                       case ZEND_JMPNZ_EX:\r
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO\r
+                       case ZEND_JMP_SET:\r
+#endif\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+                       case ZEND_JMP_SET_VAR:\r
+#endif\r
+                               ZEND_OP2(opline).opline_num = ZEND_OP2(opline).jmp_addr - op_array->opcodes;\r
+                               break;\r
+               }\r
+               opline++;\r
+       }\r
+\r
+       /* Do actual optimizations */\r
+       zend_optimize(op_array, script, constants TSRMLS_CC);   \r
+       \r
+       /* Redo pass_two() */\r
+       opline = op_array->opcodes;\r
+       end = opline + op_array->last;\r
+       while (opline < end) {\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+               if (opline->op1_type == IS_CONST) {\r
+                       opline->op1.zv = &op_array->literals[opline->op1.constant].constant;\r
+               }\r
+               if (opline->op2_type == IS_CONST) {\r
+                       opline->op2.zv = &op_array->literals[opline->op2.constant].constant;\r
+               }\r
+#endif\r
+               switch (opline->opcode) {\r
+                       case ZEND_JMP:\r
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO\r
+                       case ZEND_GOTO:\r
+#endif\r
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO\r
+                       case ZEND_FAST_CALL:\r
+#endif\r
+                               ZEND_OP1(opline).jmp_addr = &op_array->opcodes[ZEND_OP1(opline).opline_num];\r
+                               break;\r
+                       case ZEND_JMPZ:\r
+                       case ZEND_JMPNZ:\r
+                       case ZEND_JMPZ_EX:\r
+                       case ZEND_JMPNZ_EX:\r
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO\r
+                       case ZEND_JMP_SET:\r
+#endif\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+                       case ZEND_JMP_SET_VAR:\r
+#endif\r
+                               ZEND_OP2(opline).jmp_addr = &op_array->opcodes[ZEND_OP2(opline).opline_num];\r
+                               break;\r
+               }\r
+               ZEND_VM_SET_OPCODE_HANDLER(opline);\r
+               opline++;\r
+       }\r
+}\r
+\r
+int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC)\r
+{\r
+       Bucket *p, *q;\r
+       HashTable *constants = NULL;\r
+\r
+       zend_accel_optimize(&script->main_op_array, script, &constants TSRMLS_CC);\r
+\r
+       p = script->function_table.pListHead;\r
+       while (p) {\r
+               zend_op_array *op_array = (zend_op_array*)p->pData;\r
+               zend_accel_optimize(op_array, script, &constants TSRMLS_CC);\r
+               p = p->pListNext;\r
+       }\r
+\r
+       p = script->class_table.pListHead;\r
+       while (p) {\r
+               zend_class_entry *ce = (zend_class_entry*)p->pDataPtr;\r
+               q = ce->function_table.pListHead;\r
+               while (q) {\r
+                       zend_op_array *op_array = (zend_op_array*)q->pData;\r
+                       if (op_array->scope == ce) {\r
+                               zend_accel_optimize(op_array, script, &constants TSRMLS_CC);\r
+                       } else if (op_array->type == ZEND_USER_FUNCTION) {\r
+                               zend_op_array *orig_op_array;\r
+                               if (zend_hash_find(&op_array->scope->function_table, q->arKey, q->nKeyLength, (void**)&orig_op_array) == SUCCESS) {\r
+                                       HashTable *ht = op_array->static_variables;\r
+                                       *op_array = *orig_op_array;\r
+                                       op_array->static_variables = ht;\r
+                               }\r
+                       }\r
+                       q = q->pListNext;\r
+               }\r
+               p = p->pListNext;\r
+       }\r
+\r
+       if (constants) {\r
+               zend_hash_destroy(constants);\r
+               efree(constants);\r
+       }\r
+\r
+       return 1;\r
+}\r
index 98275a20aae0e992a6d10aacd77f02ae7acda865..1775994b6080e9e25f3583ca76036ad27bd25ea0 100644 (file)
@@ -44,6 +44,4 @@
 \r
 #define DEFAULT_OPTIMIZATION_LEVEL  "0xFFFFFFFF"\r
 \r
-void zend_optimizer(zend_op_array *op_array TSRMLS_DC);\r
-\r
 #endif\r
index b62f245f4c21b5a506d2923b511ca68f6c92fbe0..9a6c763ffaa1ce02b6924f2d58b57028d3131c9a 100644 (file)
@@ -1126,6 +1126,10 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
                return new_persistent_script;
        }
 
+       if (!zend_accel_script_optimize(new_persistent_script TSRMLS_CC)) {
+               return new_persistent_script;
+       }
+
        /* exclusive lock */
        zend_shared_alloc_lock(TSRMLS_C);
 
@@ -2731,19 +2735,6 @@ void accelerator_shm_read_unlock(TSRMLS_D)
        }
 }
 
-static void accel_op_array_handler(zend_op_array *op_array)
-{
-       TSRMLS_FETCH();
-
-       if (ZCG(enabled) &&
-           accel_startup_ok &&
-           ZCSG(accelerator_enabled) &&
-           !ZSMMG(memory_exhausted) &&
-           !ZCSG(restart_pending)) {
-               zend_optimizer(op_array TSRMLS_CC);
-       }
-}
-
 ZEND_EXT_API zend_extension zend_extension_entry = {
        ACCELERATOR_PRODUCT_NAME,               /* name */
        ACCELERATOR_VERSION,                                    /* version */
@@ -2755,7 +2746,7 @@ ZEND_EXT_API zend_extension zend_extension_entry = {
        accel_activate,                                                 /* per-script activation */
        accel_deactivate,                                               /* per-script deactivation */
        NULL,                                                                   /* message handler */
-       accel_op_array_handler,                                 /* op_array handler */
+       NULL,                                                                   /* op_array handler */
        NULL,                                                                   /* extended statement handler */
        NULL,                                                                   /* extended fcall begin handler */
        NULL,                                                                   /* extended fcall end handler */
index 85f95708a28e2ca7b10fd76ce3edd1bdc9fd79c8..063c95102755cedd9b327284fdce3270a0c40cee 100644 (file)
@@ -319,6 +319,7 @@ extern char *zps_api_failure_reason;
 void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC);
 void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC);
 int  zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC);
+int  zend_accel_script_optimize(zend_persistent_script *persistent_script TSRMLS_DC);
 int  accelerator_shm_read_lock(TSRMLS_D);
 void accelerator_shm_read_unlock(TSRMLS_D);