PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/opcache - zend_persist.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 263 459 57.3 %
Date: 2018-07-27 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend OPcache                                                         |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2018 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Stanislav Malyshev <stas@zend.com>                          |
      18             :    |          Dmitry Stogov <dmitry@zend.com>                             |
      19             :    +----------------------------------------------------------------------+
      20             : */
      21             : 
      22             : #include "zend.h"
      23             : #include "ZendAccelerator.h"
      24             : #include "zend_persist.h"
      25             : #include "zend_extensions.h"
      26             : #include "zend_shared_alloc.h"
      27             : #include "zend_vm.h"
      28             : #include "zend_constants.h"
      29             : #include "zend_operators.h"
      30             : 
      31             : #define zend_accel_store(p, size) \
      32             :             (p = _zend_shared_memdup((void*)p, size, 1))
      33             : #define zend_accel_memdup(p, size) \
      34             :             _zend_shared_memdup((void*)p, size, 0)
      35             : 
      36             : #ifdef HAVE_OPCACHE_FILE_CACHE
      37             : #define zend_set_str_gc_flags(str) do { \
      38             :         if (file_cache_only) { \
      39             :                 GC_FLAGS(str) = IS_STR_INTERNED; \
      40             :         } else { \
      41             :                 GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT; \
      42             :         } \
      43             : } while (0)
      44             : #else
      45             : #define zend_set_str_gc_flags(str) GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT
      46             : #endif
      47             : 
      48             : #define zend_accel_store_string(str) do { \
      49             :                 zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
      50             :                 if (new_str) { \
      51             :                         zend_string_release(str); \
      52             :                         str = new_str; \
      53             :                 } else { \
      54             :                 new_str = zend_accel_memdup((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
      55             :                         zend_string_release(str); \
      56             :                 str = new_str; \
      57             :                 zend_string_hash_val(str); \
      58             :                 zend_set_str_gc_flags(str); \
      59             :                 } \
      60             :     } while (0)
      61             : #define zend_accel_memdup_string(str) do { \
      62             :                 str = zend_accel_memdup(str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
      63             :         zend_string_hash_val(str); \
      64             :                 zend_set_str_gc_flags(str); \
      65             :         } while (0)
      66             : #define zend_accel_store_interned_string(str) do { \
      67             :                 if (!IS_ACCEL_INTERNED(str)) { \
      68             :                         zend_accel_store_string(str); \
      69             :                 } \
      70             :         } while (0)
      71             : #define zend_accel_memdup_interned_string(str) do { \
      72             :                 if (!IS_ACCEL_INTERNED(str)) { \
      73             :                         zend_accel_memdup_string(str); \
      74             :                 } \
      75             :         } while (0)
      76             : 
      77             : typedef void (*zend_persist_func_t)(zval*);
      78             : 
      79             : static void zend_persist_zval(zval *z);
      80             : 
      81             : static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
      82             :         {HT_INVALID_IDX, HT_INVALID_IDX};
      83             : 
      84        1454 : static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement)
      85             : {
      86             :         uint32_t idx, nIndex;
      87             :         Bucket *p;
      88             : 
      89        1454 :         ht->pDestructor = NULL;
      90             : 
      91        1454 :         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
      92         691 :                 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
      93         690 :                         HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
      94             :                 } else {
      95           1 :                         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
      96             :                 }
      97         691 :                 return;
      98             :         }
      99         763 :         if (ht->nNumUsed == 0) {
     100         569 :                 efree(HT_GET_DATA_ADDR(ht));
     101         569 :                 ht->nTableMask = HT_MIN_MASK;
     102         569 :                 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
     103         568 :                         HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
     104             :                 } else {
     105           1 :                         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     106             :                 }
     107         569 :                 ht->u.flags &= ~HASH_FLAG_INITIALIZED;
     108         569 :                 return;
     109             :         }
     110         194 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     111          24 :                 void *data = HT_GET_DATA_ADDR(ht);
     112          24 :                 zend_accel_store(data, HT_USED_SIZE(ht));
     113          24 :                 HT_SET_DATA_ADDR(ht, data);
     114         170 :         } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 2) {
     115             :                 /* compact table */
     116         164 :                 void *old_data = HT_GET_DATA_ADDR(ht);
     117         164 :                 Bucket *old_buckets = ht->arData;
     118             :                 uint32_t hash_size;
     119             : 
     120         164 :                 if (ht->nNumUsed <= HT_MIN_SIZE) {
     121         164 :                         hash_size = HT_MIN_SIZE;
     122             :                 } else {
     123           0 :                         hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
     124           0 :                         while (hash_size >> 1 > ht->nNumUsed) {
     125           0 :                                 hash_size >>= 1;
     126             :                         }
     127             :                 }
     128         164 :                 ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
     129         164 :                 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     130         164 :                 HT_SET_DATA_ADDR(ht, ZCG(mem));
     131         164 :                 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
     132         164 :                 HT_HASH_RESET(ht);
     133         164 :                 memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
     134         164 :                 efree(old_data);
     135             : 
     136         392 :                 for (idx = 0; idx < ht->nNumUsed; idx++) {
     137         228 :                         p = ht->arData + idx;
     138         456 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
     139             : 
     140             :                         /* persist bucket and key */
     141         209 :                         if (p->key) {
     142         209 :                                 zend_accel_store_interned_string(p->key);
     143             :                         }
     144             : 
     145             :                         /* persist the data itself */
     146         209 :                         pPersistElement(&p->val);
     147             : 
     148         209 :                         nIndex = p->h | ht->nTableMask;
     149         209 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     150         209 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     151             :                 }
     152         164 :                 return;
     153             :         } else {
     154           6 :                 void *data = ZCG(mem);
     155           6 :                 void *old_data = HT_GET_DATA_ADDR(ht);
     156             : 
     157           6 :                 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     158           6 :                 ZCG(mem) = (void*)((char*)data + HT_USED_SIZE(ht));
     159           6 :                 memcpy(data, old_data, HT_USED_SIZE(ht));
     160           6 :                 efree(old_data);
     161           6 :                 HT_SET_DATA_ADDR(ht, data);
     162             :         }
     163             : 
     164         169 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
     165         139 :                 p = ht->arData + idx;
     166         278 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     167             : 
     168             :                 /* persist bucket and key */
     169         135 :                 if (p->key) {
     170          67 :                         zend_accel_store_interned_string(p->key);
     171             :                 }
     172             : 
     173             :                 /* persist the data itself */
     174         135 :                 pPersistElement(&p->val);
     175             :         }
     176             : }
     177             : 
     178           0 : static void zend_hash_persist_immutable(HashTable *ht)
     179             : {
     180             :         uint32_t idx, nIndex;
     181             :         Bucket *p;
     182             : 
     183           0 :         ht->pDestructor = NULL;
     184             : 
     185           0 :         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
     186           0 :                 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
     187           0 :                         HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
     188             :                 } else {
     189           0 :                         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     190             :                 }
     191           0 :                 return;
     192             :         }
     193           0 :         if (ht->nNumUsed == 0) {
     194           0 :                 efree(HT_GET_DATA_ADDR(ht));
     195           0 :                 ht->nTableMask = HT_MIN_MASK;
     196           0 :                 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
     197           0 :                         HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
     198             :                 } else {
     199           0 :                         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     200             :                 }
     201           0 :                 ht->u.flags &= ~HASH_FLAG_INITIALIZED;
     202           0 :                 return;
     203             :         }
     204           0 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     205           0 :                 HT_SET_DATA_ADDR(ht, zend_accel_memdup(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht)));
     206           0 :         } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 2) {
     207             :                 /* compact table */
     208           0 :                 void *old_data = HT_GET_DATA_ADDR(ht);
     209           0 :                 Bucket *old_buckets = ht->arData;
     210             :                 uint32_t hash_size;
     211             : 
     212           0 :                 if (ht->nNumUsed <= HT_MIN_SIZE) {
     213           0 :                         hash_size = HT_MIN_SIZE;
     214             :                 } else {
     215           0 :                         hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
     216           0 :                         while (hash_size >> 1 > ht->nNumUsed) {
     217           0 :                                 hash_size >>= 1;
     218             :                         }
     219             :                 }
     220           0 :                 ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
     221           0 :                 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     222           0 :                 HT_SET_DATA_ADDR(ht, ZCG(mem));
     223           0 :                 ZCG(mem) = (void*)((char*)ZCG(mem) + (hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket)));
     224           0 :                 HT_HASH_RESET(ht);
     225           0 :                 memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
     226           0 :                 efree(old_data);
     227             : 
     228           0 :                 for (idx = 0; idx < ht->nNumUsed; idx++) {
     229           0 :                         p = ht->arData + idx;
     230           0 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
     231             : 
     232             :                         /* persist bucket and key */
     233           0 :                         if (p->key) {
     234           0 :                                 zend_accel_memdup_interned_string(p->key);
     235             :                         }
     236             : 
     237             :                         /* persist the data itself */
     238           0 :                         zend_persist_zval(&p->val);
     239             : 
     240           0 :                         nIndex = p->h | ht->nTableMask;
     241           0 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     242           0 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     243             :                 }
     244           0 :                 return;
     245             :         } else {
     246           0 :                 void *data = ZCG(mem);
     247             : 
     248           0 :                 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     249           0 :                 ZCG(mem) = (void*)((char*)data + HT_USED_SIZE(ht));
     250           0 :                 memcpy(data, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
     251           0 :                 HT_SET_DATA_ADDR(ht, data);
     252             :         }
     253           0 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
     254           0 :                 p = ht->arData + idx;
     255           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     256             : 
     257             :                 /* persist bucket and key */
     258           0 :                 if (p->key) {
     259           0 :                         zend_accel_memdup_interned_string(p->key);
     260             :                 }
     261             : 
     262             :                 /* persist the data itself */
     263           0 :                 zend_persist_zval(&p->val);
     264             :         }
     265             : }
     266             : 
     267           0 : static zend_ast *zend_persist_ast(zend_ast *ast)
     268             : {
     269             :         uint32_t i;
     270             :         zend_ast *node;
     271             : 
     272           0 :         if (ast->kind == ZEND_AST_ZVAL) {
     273           0 :                 zend_ast_zval *copy = zend_accel_memdup(ast, sizeof(zend_ast_zval));
     274           0 :                 zend_persist_zval(&copy->val);
     275           0 :                 node = (zend_ast *) copy;
     276           0 :         } else if (zend_ast_is_list(ast)) {
     277           0 :                 zend_ast_list *list = zend_ast_get_list(ast);
     278           0 :                 zend_ast_list *copy = zend_accel_memdup(ast,
     279             :                         sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
     280           0 :                 for (i = 0; i < list->children; i++) {
     281           0 :                         if (copy->child[i]) {
     282           0 :                                 copy->child[i] = zend_persist_ast(copy->child[i]);
     283             :                         }
     284             :                 }
     285           0 :                 node = (zend_ast *) copy;
     286             :         } else {
     287           0 :                 uint32_t children = zend_ast_get_num_children(ast);
     288           0 :                 node = zend_accel_memdup(ast, sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children);
     289           0 :                 for (i = 0; i < children; i++) {
     290           0 :                         if (node->child[i]) {
     291           0 :                                 node->child[i] = zend_persist_ast(node->child[i]);
     292             :                         }
     293             :                 }
     294             :         }
     295             : 
     296           0 :         efree(ast);
     297           0 :         return node;
     298             : }
     299             : 
     300        4421 : static void zend_persist_zval(zval *z)
     301             : {
     302             :         zend_uchar flags;
     303             :         void *new_ptr;
     304             : 
     305        4421 :         switch (Z_TYPE_P(z)) {
     306        3323 :                 case IS_STRING:
     307             :                 case IS_CONSTANT:
     308        3323 :                         flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT);
     309        3335 :                         zend_accel_store_interned_string(Z_STR_P(z));
     310        3323 :                         Z_GC_FLAGS_P(z) |= flags;
     311        3323 :                         Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
     312        3323 :                         if (Z_TYPE_P(z) == IS_CONSTANT) {
     313           0 :                                 Z_TYPE_FLAGS_P(z) |= IS_TYPE_IMMUTABLE;
     314             :                         }
     315        3323 :                         break;
     316          94 :                 case IS_ARRAY:
     317          94 :                         new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
     318          94 :                         if (new_ptr) {
     319           1 :                                 Z_ARR_P(z) = new_ptr;
     320           1 :                                 Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
     321             :                         } else {
     322          93 :                                 if (Z_IMMUTABLE_P(z)) {
     323           0 :                                         Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array));
     324           0 :                                         zend_hash_persist_immutable(Z_ARRVAL_P(z));
     325             :                                 } else {
     326          93 :                                         GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
     327          93 :                                         zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
     328          93 :                                         zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval);
     329             :                                         /* make immutable array */
     330          93 :                                         Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
     331          93 :                                         GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
     332          93 :                                         GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
     333          93 :                                         Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
     334          93 :                                         Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     335             :                                 }
     336             :                         }
     337          94 :                         break;
     338           0 :                 case IS_REFERENCE:
     339           0 :                         new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z));
     340           0 :                         if (new_ptr) {
     341           0 :                                 Z_REF_P(z) = new_ptr;
     342             :                         } else {
     343           0 :                                 zend_accel_store(Z_REF_P(z), sizeof(zend_reference));
     344           0 :                                 zend_persist_zval(Z_REFVAL_P(z));
     345             :                         }
     346           0 :                         break;
     347           0 :                 case IS_CONSTANT_AST:
     348           0 :                         new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
     349           0 :                         if (new_ptr) {
     350           0 :                                 Z_AST_P(z) = new_ptr;
     351           0 :                                 Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_IMMUTABLE;
     352             :                         } else {
     353           0 :                                 zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
     354           0 :                                 Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
     355           0 :                                 Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_IMMUTABLE;
     356           0 :                                 GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
     357             :                         }
     358           0 :                         break;
     359             :         }
     360        4421 : }
     361             : 
     362         729 : static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script)
     363             : {
     364         729 :         int already_stored = 0;
     365             :         zend_op *persist_ptr;
     366         729 :         zval *orig_literals = NULL;
     367             : 
     368         729 :         if (op_array->type != ZEND_USER_FUNCTION) {
     369           0 :                 return;
     370             :         }
     371             : 
     372         729 :         if (op_array->refcount && --(*op_array->refcount) == 0) {
     373         729 :                 efree(op_array->refcount);
     374             :         }
     375         729 :         op_array->refcount = NULL;
     376             : 
     377         729 :         if (main_persistent_script) {
     378         622 :                 zend_execute_data *orig_execute_data = EG(current_execute_data);
     379             :                 zend_execute_data fake_execute_data;
     380             :                 zval *offset;
     381             : 
     382         622 :                 memset(&fake_execute_data, 0, sizeof(fake_execute_data));
     383         622 :                 fake_execute_data.func = (zend_function*)op_array;
     384         622 :                 EG(current_execute_data) = &fake_execute_data;
     385         622 :                 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
     386          95 :                         main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset);
     387             :                 }
     388         622 :                 EG(current_execute_data) = orig_execute_data;
     389             :         }
     390             : 
     391         729 :         if (op_array->static_variables) {
     392          21 :                 HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
     393             : 
     394          21 :                 if (stored) {
     395           0 :                         op_array->static_variables = stored;
     396             :                 } else {
     397          21 :                         zend_hash_persist(op_array->static_variables, zend_persist_zval);
     398          21 :                         zend_accel_store(op_array->static_variables, sizeof(HashTable));
     399             :                         /* make immutable array */
     400          21 :                         GC_REFCOUNT(op_array->static_variables) = 2;
     401          21 :                         GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
     402          21 :                         op_array->static_variables->u.flags |= HASH_FLAG_STATIC_KEYS;
     403          21 :                         op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     404             :                 }
     405             :         }
     406             : 
     407         729 :         if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
     408           0 :                 already_stored = 1;
     409             :         }
     410             : 
     411         729 :         if (op_array->literals) {
     412         729 :                 if (already_stored) {
     413           0 :                         orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
     414           0 :                         ZEND_ASSERT(orig_literals != NULL);
     415           0 :                         op_array->literals = orig_literals;
     416             :                 } else {
     417         729 :                         zval *p = zend_accel_memdup(op_array->literals, sizeof(zval) * op_array->last_literal);
     418         729 :                         zval *end = p + op_array->last_literal;
     419         729 :                         orig_literals = op_array->literals;
     420         729 :                         op_array->literals = p;
     421        5674 :                         while (p < end) {
     422        4216 :                                 zend_persist_zval(p);
     423        4216 :                                 p++;
     424             :                         }
     425         729 :                         efree(orig_literals);
     426             :                 }
     427             :         }
     428             : 
     429         729 :         if (already_stored) {
     430           0 :                 persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
     431           0 :                 ZEND_ASSERT(persist_ptr != NULL);
     432           0 :                 op_array->opcodes = persist_ptr;
     433             :         } else {
     434         729 :                 zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last);
     435             : #if ZEND_USE_ABS_CONST_ADDR || ZEND_USE_ABS_JMP_ADDR
     436             :                 zend_op *opline = new_opcodes;
     437             :                 zend_op *end = new_opcodes + op_array->last;
     438             :                 int offset = 0;
     439             : 
     440             :                 for (; opline < end ; opline++, offset++) {
     441             : # if ZEND_USE_ABS_CONST_ADDR
     442             :                         if (opline->op1_type == IS_CONST) {
     443             :                                 opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
     444             :                         }
     445             :                         if (opline->op2_type == IS_CONST) {
     446             :                                 opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
     447             :                         }
     448             : # endif
     449             : # if ZEND_USE_ABS_JMP_ADDR
     450             :                         if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
     451             :                                 /* fix jumps to point to new array */
     452             :                                 switch (opline->opcode) {
     453             :                                         case ZEND_JMP:
     454             :                                         case ZEND_FAST_CALL:
     455             :                                                 opline->op1.jmp_addr = &new_opcodes[opline->op1.jmp_addr - op_array->opcodes];
     456             :                                                 break;
     457             :                                         case ZEND_JMPZNZ:
     458             :                                                 /* relative extended_value don't have to be changed */
     459             :                                                 /* break omitted intentionally */
     460             :                                         case ZEND_JMPZ:
     461             :                                         case ZEND_JMPNZ:
     462             :                                         case ZEND_JMPZ_EX:
     463             :                                         case ZEND_JMPNZ_EX:
     464             :                                         case ZEND_JMP_SET:
     465             :                                         case ZEND_COALESCE:
     466             :                                         case ZEND_FE_RESET_R:
     467             :                                         case ZEND_FE_RESET_RW:
     468             :                                         case ZEND_ASSERT_CHECK:
     469             :                                                 opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
     470             :                                                 break;
     471             :                                         case ZEND_DECLARE_ANON_CLASS:
     472             :                                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
     473             :                                         case ZEND_FE_FETCH_R:
     474             :                                         case ZEND_FE_FETCH_RW:
     475             :                                                 /* relative extended_value don't have to be changed */
     476             :                                                 break;
     477             :                                 }
     478             :                         }
     479             : # endif
     480             :                 }
     481             : #endif
     482             : 
     483         729 :                 efree(op_array->opcodes);
     484         729 :                 op_array->opcodes = new_opcodes;
     485             : 
     486         729 :                 if (op_array->run_time_cache) {
     487           0 :                         efree(op_array->run_time_cache);
     488           0 :                         op_array->run_time_cache = NULL;
     489             :                 }
     490             :         }
     491             : 
     492         729 :         if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) {
     493             :                 zend_string *new_name;
     494           0 :                 if (already_stored) {
     495           0 :                         new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
     496           0 :                         ZEND_ASSERT(new_name != NULL);
     497           0 :                         op_array->function_name = new_name;
     498             :                 } else {
     499           0 :                         zend_accel_store_string(op_array->function_name);
     500             :                 }
     501             :         }
     502             : 
     503         729 :         if (op_array->filename) {
     504             :                 /* do not free! PHP has centralized filename storage, compiler will free it */
     505        1458 :                 zend_accel_memdup_string(op_array->filename);
     506             :         }
     507             : 
     508         729 :         if (op_array->arg_info) {
     509          53 :                 zend_arg_info *arg_info = op_array->arg_info;
     510          53 :                 uint32_t num_args = op_array->num_args;
     511             : 
     512          53 :                 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
     513           5 :                         arg_info--;
     514           5 :                         num_args++;
     515             :                 }
     516          53 :                 if (already_stored) {
     517           0 :                         arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
     518           0 :                         ZEND_ASSERT(arg_info != NULL);
     519             :                 } else {
     520             :                         uint32_t i;
     521             : 
     522          53 :                         if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
     523           0 :                                 num_args++;
     524             :                         }
     525          53 :                         zend_accel_store(arg_info, sizeof(zend_arg_info) * num_args);
     526         117 :                         for (i = 0; i < num_args; i++) {
     527          64 :                                 if (arg_info[i].name) {
     528          59 :                                         zend_accel_store_interned_string(arg_info[i].name);
     529             :                                 }
     530          64 :                                 if (arg_info[i].class_name) {
     531           4 :                                         zend_accel_store_interned_string(arg_info[i].class_name);
     532             :                                 }
     533             :                         }
     534             :                 }
     535          53 :                 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
     536           5 :                         arg_info++;
     537             :                 }
     538          53 :                 op_array->arg_info = arg_info;
     539             :         }
     540             : 
     541         729 :         if (op_array->live_range) {
     542          93 :                 zend_accel_store(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
     543             :         }
     544             : 
     545         729 :         if (op_array->scope) {
     546          26 :                 op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
     547             :         }
     548             : 
     549         729 :         if (op_array->doc_comment) {
     550           0 :                 if (ZCG(accel_directives).save_comments) {
     551           0 :                         if (already_stored) {
     552           0 :                                 op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
     553           0 :                                 ZEND_ASSERT(op_array->doc_comment != NULL);
     554             :                         } else {
     555           0 :                                 zend_accel_store_string(op_array->doc_comment);
     556             :                         }
     557             :                 } else {
     558           0 :                         if (!already_stored) {
     559           0 :                                 zend_string_release(op_array->doc_comment);
     560             :                         }
     561           0 :                         op_array->doc_comment = NULL;
     562             :                 }
     563             :         }
     564             : 
     565         729 :         if (op_array->try_catch_array) {
     566          14 :                 zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
     567             :         }
     568             : 
     569         729 :         if (op_array->vars) {
     570         150 :                 if (already_stored) {
     571           0 :                         persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars);
     572           0 :                         ZEND_ASSERT(persist_ptr != NULL);
     573           0 :                         op_array->vars = (zend_string**)persist_ptr;
     574             :                 } else {
     575             :                         int i;
     576         150 :                         zend_accel_store(op_array->vars, sizeof(zend_string*) * op_array->last_var);
     577         492 :                         for (i = 0; i < op_array->last_var; i++) {
     578         342 :                                 zend_accel_store_interned_string(op_array->vars[i]);
     579             :                         }
     580             :                 }
     581             :         }
     582             : 
     583             :         /* "prototype" may be undefined if "scope" isn't set */
     584         729 :         if (op_array->scope && op_array->prototype) {
     585           4 :                 if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
     586           2 :                         op_array->prototype = (union _zend_function*)persist_ptr;
     587             :                 }
     588             :         } else {
     589         727 :                 op_array->prototype = NULL;
     590             :         }
     591             : 
     592         729 :         ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
     593             : }
     594             : 
     595         107 : static void zend_persist_op_array(zval *zv)
     596             : {
     597         107 :         zend_op_array *op_array = Z_PTR_P(zv);
     598         107 :         zend_op_array *old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
     599         107 :         if (old_op_array) {
     600           0 :                 Z_PTR_P(zv) = old_op_array;
     601           0 :                 if (op_array->refcount && --(*op_array->refcount) == 0) {
     602           0 :                         efree(op_array->refcount);
     603             :                 }
     604           0 :                 return;
     605             :         }
     606         107 :         memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_op_array));
     607         107 :         zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
     608         107 :         Z_PTR_P(zv) = ZCG(arena_mem);
     609         107 :         ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_op_array)));
     610         107 :         zend_persist_op_array_ex(Z_PTR_P(zv), NULL);
     611             : }
     612             : 
     613          11 : static void zend_persist_property_info(zval *zv)
     614             : {
     615          11 :         zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
     616             : 
     617          11 :         if (prop) {
     618           0 :                 Z_PTR_P(zv) = prop;
     619           0 :                 return;
     620             :         }
     621          11 :         memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_property_info));
     622          11 :         zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
     623          11 :         prop = Z_PTR_P(zv) = ZCG(arena_mem);
     624          11 :         ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_property_info)));
     625          11 :         prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
     626          11 :         zend_accel_store_interned_string(prop->name);
     627          11 :         if (prop->doc_comment) {
     628           0 :                 if (ZCG(accel_directives).save_comments) {
     629           0 :                         zend_accel_store_string(prop->doc_comment);
     630             :                 } else {
     631           0 :                         if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
     632           0 :                                 zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
     633             :                         }
     634           0 :                         zend_string_release(prop->doc_comment);
     635           0 :                         prop->doc_comment = NULL;
     636             :                 }
     637             :         }
     638             : }
     639             : 
     640          14 : static void zend_persist_class_constant(zval *zv)
     641             : {
     642          14 :         zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
     643             : 
     644          14 :         if (c) {
     645           0 :                 Z_PTR_P(zv) = c;
     646           0 :                 return;
     647             :         }
     648          14 :         memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_constant));
     649          14 :         zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
     650          14 :         c = Z_PTR_P(zv) = ZCG(arena_mem);
     651          14 :         ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_constant)));
     652          14 :         zend_persist_zval(&c->value);
     653          14 :         c->ce = zend_shared_alloc_get_xlat_entry(c->ce);
     654          14 :         if (c->doc_comment) {
     655           0 :                 if (ZCG(accel_directives).save_comments) {
     656           0 :                         zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
     657           0 :                         if (doc_comment) {
     658           0 :                                 c->doc_comment = doc_comment;
     659             :                         } else {
     660           0 :                                 zend_accel_store_string(c->doc_comment);
     661             :                         }
     662             :                 } else {
     663           0 :                         zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
     664           0 :                         if (!doc_comment) {
     665           0 :                                 zend_shared_alloc_register_xlat_entry(c->doc_comment, c->doc_comment);
     666           0 :                                 zend_string_release(c->doc_comment);
     667             :                         }
     668           0 :                         c->doc_comment = NULL;
     669             :                 }
     670             :         }
     671             : }
     672             : 
     673          32 : static void zend_persist_class_entry(zval *zv)
     674             : {
     675          32 :         zend_class_entry *ce = Z_PTR_P(zv);
     676             : 
     677          32 :         if (ce->type == ZEND_USER_CLASS) {
     678          32 :                 memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_entry));
     679          32 :                 zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
     680          32 :                 ce = Z_PTR_P(zv) = ZCG(arena_mem);
     681          32 :                 ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_entry)));
     682          32 :                 zend_accel_store_interned_string(ce->name);
     683          32 :                 zend_hash_persist(&ce->function_table, zend_persist_op_array);
     684          32 :                 if (ce->default_properties_table) {
     685             :                     int i;
     686             : 
     687           3 :                         zend_accel_store(ce->default_properties_table, sizeof(zval) * ce->default_properties_count);
     688           6 :                         for (i = 0; i < ce->default_properties_count; i++) {
     689           3 :                                 zend_persist_zval(&ce->default_properties_table[i]);
     690             :                         }
     691             :                 }
     692          32 :                 if (ce->default_static_members_table) {
     693             :                     int i;
     694             : 
     695           6 :                         zend_accel_store(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
     696          14 :                         for (i = 0; i < ce->default_static_members_count; i++) {
     697           8 :                                 zend_persist_zval(&ce->default_static_members_table[i]);
     698             :                         }
     699             :                 }
     700          32 :                 ce->static_members_table = NULL;
     701             : 
     702          32 :                 zend_hash_persist(&ce->constants_table, zend_persist_class_constant);
     703             : 
     704          32 :                 if (ce->info.user.filename) {
     705             :                         /* do not free! PHP has centralized filename storage, compiler will free it */
     706          64 :                         zend_accel_memdup_string(ce->info.user.filename);
     707             :                 }
     708          32 :                 if (ce->info.user.doc_comment) {
     709           0 :                         if (ZCG(accel_directives).save_comments) {
     710           0 :                                 zend_accel_store_string(ce->info.user.doc_comment);
     711             :                         } else {
     712           0 :                                 if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) {
     713           0 :                                         zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment);
     714           0 :                                         zend_string_release(ce->info.user.doc_comment);
     715             :                                 }
     716           0 :                                 ce->info.user.doc_comment = NULL;
     717             :                         }
     718             :                 }
     719          32 :                 zend_hash_persist(&ce->properties_info, zend_persist_property_info);
     720          32 :                 if (ce->num_interfaces && ce->interfaces) {
     721           0 :                         efree(ce->interfaces);
     722             :                 }
     723          32 :                 ce->interfaces = NULL; /* will be filled in on fetch */
     724             : 
     725          32 :                 if (ce->num_traits && ce->traits) {
     726           0 :                         efree(ce->traits);
     727             :                 }
     728          32 :                 ce->traits = NULL;
     729             : 
     730          32 :                 if (ce->trait_aliases) {
     731           0 :                         int i = 0;
     732           0 :                         while (ce->trait_aliases[i]) {
     733           0 :                                 if (ce->trait_aliases[i]->trait_method) {
     734           0 :                                         if (ce->trait_aliases[i]->trait_method->method_name) {
     735           0 :                                                 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->method_name);
     736             :                                         }
     737           0 :                                         if (ce->trait_aliases[i]->trait_method->class_name) {
     738           0 :                                                 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->class_name);
     739             :                                         }
     740           0 :                                         ce->trait_aliases[i]->trait_method->ce = NULL;
     741           0 :                                         zend_accel_store(ce->trait_aliases[i]->trait_method,
     742             :                                                 sizeof(zend_trait_method_reference));
     743             :                                 }
     744             : 
     745           0 :                                 if (ce->trait_aliases[i]->alias) {
     746           0 :                                         zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
     747             :                                 }
     748             : 
     749           0 :                                 zend_accel_store(ce->trait_aliases[i], sizeof(zend_trait_alias));
     750           0 :                                 i++;
     751             :                         }
     752             : 
     753           0 :                         zend_accel_store(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
     754             :                 }
     755             : 
     756          32 :                 if (ce->trait_precedences) {
     757           0 :                         int i = 0;
     758             : 
     759           0 :                         while (ce->trait_precedences[i]) {
     760           0 :                                 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->method_name);
     761           0 :                                 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->class_name);
     762           0 :                                 ce->trait_precedences[i]->trait_method->ce = NULL;
     763           0 :                                 zend_accel_store(ce->trait_precedences[i]->trait_method,
     764             :                                         sizeof(zend_trait_method_reference));
     765             : 
     766           0 :                                 if (ce->trait_precedences[i]->exclude_from_classes) {
     767           0 :                                         int j = 0;
     768             : 
     769           0 :                                         while (ce->trait_precedences[i]->exclude_from_classes[j].class_name) {
     770           0 :                                                 zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_from_classes[j].class_name);
     771           0 :                                                 j++;
     772             :                                         }
     773           0 :                                         zend_accel_store(ce->trait_precedences[i]->exclude_from_classes,
     774             :                                                 sizeof(zend_class_entry*) * (j + 1));
     775             :                                 }
     776             : 
     777           0 :                                 zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence));
     778           0 :                                 i++;
     779             :                         }
     780           0 :                         zend_accel_store(
     781             :                                 ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
     782             :                 }
     783             :         }
     784          32 : }
     785             : 
     786             : //static int zend_update_property_info_ce(zval *zv)
     787             : //{
     788             : //      zend_property_info *prop = Z_PTR_P(zv);
     789             : //
     790             : //      prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
     791             : //      return 0;
     792             : //}
     793             : 
     794          32 : static int zend_update_parent_ce(zval *zv)
     795             : {
     796          32 :         zend_class_entry *ce = Z_PTR_P(zv);
     797             : 
     798          32 :         if (ce->parent) {
     799           3 :                 ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
     800             :         }
     801             : 
     802             :         /* update methods */
     803          32 :         if (ce->constructor) {
     804           1 :                 ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
     805             :         }
     806          32 :         if (ce->destructor) {
     807           0 :                 ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
     808             :         }
     809          32 :         if (ce->clone) {
     810           1 :                 ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
     811             :         }
     812          32 :         if (ce->__get) {
     813           1 :                 ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
     814             :         }
     815          32 :         if (ce->__set) {
     816           0 :                 ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
     817             :         }
     818          32 :         if (ce->__call) {
     819           0 :                 ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
     820             :         }
     821          32 :         if (ce->serialize_func) {
     822           0 :                 ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
     823             :         }
     824          32 :         if (ce->unserialize_func) {
     825           0 :                 ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
     826             :         }
     827          32 :         if (ce->__isset) {
     828           0 :                 ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
     829             :         }
     830          32 :         if (ce->__unset) {
     831           0 :                 ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
     832             :         }
     833          32 :         if (ce->__tostring) {
     834           0 :                 ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
     835             :         }
     836          32 :         if (ce->__callstatic) {
     837           0 :                 ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
     838             :         }
     839          32 :         if (ce->__debugInfo) {
     840           0 :                 ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
     841             :         }
     842             : //      zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
     843          32 :         return 0;
     844             : }
     845             : 
     846         622 : static void zend_accel_persist_class_table(HashTable *class_table)
     847             : {
     848         622 :     zend_hash_persist(class_table, zend_persist_class_entry);
     849         622 :         zend_hash_apply(class_table, (apply_func_t) zend_update_parent_ce);
     850         622 : }
     851             : 
     852         622 : zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length, int for_shm)
     853             : {
     854         622 :         script->mem = ZCG(mem);
     855             : 
     856         622 :         ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     857         622 :         zend_shared_alloc_clear_xlat_table();
     858             : 
     859         622 :         zend_accel_store(script, sizeof(zend_persistent_script));
     860         622 :         if (key && *key) {
     861         613 :                 *key = zend_accel_memdup(*key, key_length + 1);
     862             :         }
     863             : 
     864         622 :         script->corrupted = 0;
     865         622 :         ZCG(current_persistent_script) = script;
     866             : 
     867         622 :         if (!for_shm) {
     868             :                 /* script is not going to be saved in SHM */
     869           1 :                 script->corrupted = 1;
     870             :         }
     871             : 
     872        1866 :         zend_accel_store_string(script->script.filename);
     873             : 
     874             : #ifdef __SSE2__
     875             :         /* Align to 64-byte boundary */
     876         622 :         ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
     877             : #else
     878             :         ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
     879             : #endif
     880             : 
     881         622 :         script->arena_mem = ZCG(arena_mem) = ZCG(mem);
     882         622 :         ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size);
     883             : 
     884         622 :         zend_accel_persist_class_table(&script->script.class_table);
     885         622 :         zend_hash_persist(&script->script.function_table, zend_persist_op_array);
     886         622 :         zend_persist_op_array_ex(&script->script.main_op_array, script);
     887             : 
     888         622 :         script->corrupted = 0;
     889         622 :         ZCG(current_persistent_script) = NULL;
     890             : 
     891         622 :         return script;
     892             : }
     893             : 
     894         622 : int zend_accel_script_persistable(zend_persistent_script *script)
     895             : {
     896         622 :         return 1;
     897             : }

Generated by: LCOV version 1.10

Generated at Sat, 28 Jul 2018 01:57:16 +0000 (23 days ago)

Copyright © 2005-2018 The PHP Group
All rights reserved.