root/ext/opcache/zend_persist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_hash_persist
  2. zend_hash_persist_immutable
  3. zend_persist_ast
  4. zend_persist_zval
  5. zend_persist_zval_static
  6. zend_persist_zval_const
  7. zend_persist_op_array_ex
  8. zend_persist_op_array
  9. zend_persist_property_info
  10. zend_persist_class_entry
  11. zend_update_parent_ce
  12. zend_accel_persist_class_table
  13. zend_accel_script_persist
  14. zend_accel_script_persistable

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

/* [<][>][^][v][top][bottom][index][help] */