root/ext/opcache/zend_accelerator_util_funcs.c

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

DEFINITIONS

This source file includes following definitions.
  1. zend_accel_destroy_zend_function
  2. zend_accel_destroy_zend_class
  3. create_persistent_script
  4. free_persistent_script
  5. is_not_internal_function
  6. zend_accel_free_user_functions
  7. zend_accel_move_user_functions
  8. copy_internal_function
  9. zend_accel_copy_internal_functions
  10. zend_clone_zval
  11. zend_ast_clone
  12. zend_hash_clone_constants
  13. zend_hash_clone_methods
  14. zend_hash_clone_prop_info
  15. zend_class_copy_ctor
  16. zend_accel_function_hash_copy
  17. zend_accel_function_hash_copy_from_shm
  18. zend_accel_class_hash_copy
  19. fast_memcpy
  20. zend_accel_load_script
  21. zend_adler32
  22. zend_accel_script_checksum

   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_API.h"
  23 #include "zend_constants.h"
  24 #include "zend_accelerator_util_funcs.h"
  25 #include "zend_persist.h"
  26 #include "zend_shared_alloc.h"
  27 
  28 #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
  29 /* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
  30 # define accel_xlat_set(old, new)       zend_hash_index_add_new_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old), (new))
  31 # define accel_xlat_get(old)            zend_hash_index_find_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old))
  32 #else
  33 # define accel_xlat_set(old, new)       zend_hash_str_add_new_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (old))
  34 # define accel_xlat_get(old)        zend_hash_str_find_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*))
  35 #endif
  36 
  37 #define ARENA_REALLOC(ptr) \
  38         (void*)(((char*)(ptr)) + ((char*)ZCG(arena_mem) - (char*)ZCG(current_persistent_script)->arena_mem))
  39 
  40 typedef int (*id_function_t)(void *, void *);
  41 typedef void (*unique_copy_ctor_func_t)(void *pElement);
  42 
  43 static zend_ast *zend_ast_clone(zend_ast *ast);
  44 
  45 static void zend_accel_destroy_zend_function(zval *zv)
  46 {
  47         zend_function *function = Z_PTR_P(zv);
  48 
  49         if (function->type == ZEND_USER_FUNCTION) {
  50                 if (function->op_array.static_variables) {
  51                         if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
  52                                 if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
  53                                         FREE_HASHTABLE(function->op_array.static_variables);
  54                                 }
  55                         }
  56                         function->op_array.static_variables = NULL;
  57                 }
  58         }
  59 
  60         destroy_zend_function(function);
  61 }
  62 
  63 static void zend_accel_destroy_zend_class(zval *zv)
  64 {
  65         zend_class_entry *ce = Z_PTR_P(zv);
  66         ce->function_table.pDestructor = zend_accel_destroy_zend_function;
  67         destroy_zend_class(zv);
  68 }
  69 
  70 zend_persistent_script* create_persistent_script(void)
  71 {
  72         zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
  73         memset(persistent_script, 0, sizeof(zend_persistent_script));
  74 
  75         zend_hash_init(&persistent_script->function_table, 128, NULL, ZEND_FUNCTION_DTOR, 0);
  76         /* class_table is usually destroyed by free_persistent_script() that
  77          * overrides destructor. ZEND_CLASS_DTOR may be used by standard
  78          * PHP compiler
  79          */
  80         zend_hash_init(&persistent_script->class_table, 16, NULL, ZEND_CLASS_DTOR, 0);
  81 
  82         return persistent_script;
  83 }
  84 
  85 void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
  86 {
  87         if (destroy_elements) {
  88                 persistent_script->function_table.pDestructor = zend_accel_destroy_zend_function;
  89                 persistent_script->class_table.pDestructor = zend_accel_destroy_zend_class;
  90         } else {
  91                 persistent_script->function_table.pDestructor = NULL;
  92                 persistent_script->class_table.pDestructor = NULL;
  93         }
  94 
  95         zend_hash_destroy(&persistent_script->function_table);
  96         zend_hash_destroy(&persistent_script->class_table);
  97 
  98         if (persistent_script->full_path) {
  99                 zend_string_release(persistent_script->full_path);
 100         }
 101 
 102         efree(persistent_script);
 103 }
 104 
 105 static int is_not_internal_function(zval *zv)
 106 {
 107         zend_function *function = Z_PTR_P(zv);
 108         return(function->type != ZEND_INTERNAL_FUNCTION);
 109 }
 110 
 111 void zend_accel_free_user_functions(HashTable *ht)
 112 {
 113         dtor_func_t orig_dtor = ht->pDestructor;
 114 
 115         ht->pDestructor = NULL;
 116         zend_hash_apply(ht, (apply_func_t) is_not_internal_function);
 117         ht->pDestructor = orig_dtor;
 118 }
 119 
 120 void zend_accel_move_user_functions(HashTable *src, HashTable *dst)
 121 {
 122         Bucket *p;
 123         dtor_func_t orig_dtor = src->pDestructor;
 124 
 125         src->pDestructor = NULL;
 126         zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
 127         ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) {
 128                 zend_function *function = Z_PTR(p->val);
 129 
 130                 if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
 131                         _zend_hash_append_ptr(dst, p->key, function);
 132                         zend_hash_del_bucket(src, p);
 133                 } else {
 134                         break;
 135                 }
 136         } ZEND_HASH_FOREACH_END();
 137         src->pDestructor = orig_dtor;
 138 }
 139 
 140 static int copy_internal_function(zval *zv, HashTable *function_table)
 141 {
 142         zend_internal_function *function = Z_PTR_P(zv);
 143         if (function->type == ZEND_INTERNAL_FUNCTION) {
 144                 zend_hash_update_mem(function_table, function->function_name, function, sizeof(zend_internal_function));
 145         }
 146         return 0;
 147 }
 148 
 149 void zend_accel_copy_internal_functions(void)
 150 {
 151         zend_hash_apply_with_argument(CG(function_table), (apply_func_arg_t)copy_internal_function, &ZCG(function_table));
 152         ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
 153 }
 154 
 155 static inline void zend_clone_zval(zval *src)
 156 {
 157         void *ptr;
 158 
 159         if (Z_TYPE_P(src) == IS_REFERENCE) {
 160                 ptr = accel_xlat_get(Z_REF_P(src));
 161                 if (ptr != NULL) {
 162                         Z_REF_P(src) = ptr;
 163                         return;
 164                 } else {
 165                         zend_reference *old = Z_REF_P(src);
 166                         ZVAL_NEW_REF(src, &old->val);
 167                         Z_REF_P(src)->gc = old->gc;
 168                         accel_xlat_set(old, Z_REF_P(src));
 169                         src = Z_REFVAL_P(src);
 170                 }
 171         }
 172         if (Z_TYPE_P(src) == IS_CONSTANT_AST) {
 173                 if (Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_AST_P(src))) != NULL) {
 174                         Z_AST_P(src) = ptr;
 175                 } else {
 176                         zend_ast_ref *old = Z_AST_P(src);
 177 
 178                         ZVAL_NEW_AST(src, old->ast);
 179                         Z_AST_P(src)->gc = old->gc;
 180                         if (Z_REFCOUNT_P(src) > 1) {
 181                                 accel_xlat_set(old, Z_AST_P(src));
 182                         }
 183                         Z_ASTVAL_P(src) = zend_ast_clone(Z_ASTVAL_P(src));
 184                 }
 185         }
 186 }
 187 
 188 static zend_ast *zend_ast_clone(zend_ast *ast)
 189 {
 190         uint32_t i;
 191 
 192         if (ast->kind == ZEND_AST_ZVAL) {
 193                 zend_ast_zval *copy = emalloc(sizeof(zend_ast_zval));
 194                 copy->kind = ZEND_AST_ZVAL;
 195                 copy->attr = ast->attr;
 196                 ZVAL_COPY_VALUE(&copy->val, zend_ast_get_zval(ast));
 197                 return (zend_ast *) copy;
 198         } else if (zend_ast_is_list(ast)) {
 199                 zend_ast_list *list = zend_ast_get_list(ast);
 200                 zend_ast_list *copy = emalloc(
 201                         sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
 202                 copy->kind = list->kind;
 203                 copy->attr = list->attr;
 204                 copy->children = list->children;
 205                 for (i = 0; i < list->children; i++) {
 206                         if (list->child[i]) {
 207                                 copy->child[i] = zend_ast_clone(list->child[i]);
 208                         } else {
 209                                 copy->child[i] = NULL;
 210                         }
 211                 }
 212                 return (zend_ast *) copy;
 213         } else {
 214                 uint32_t children = zend_ast_get_num_children(ast);
 215                 zend_ast *copy = emalloc(sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children);
 216                 copy->kind = ast->kind;
 217                 copy->attr = ast->attr;
 218                 for (i = 0; i < children; i++) {
 219                         if (ast->child[i]) {
 220                                 copy->child[i] = zend_ast_clone(ast->child[i]);
 221                         } else {
 222                                 copy->child[i] = NULL;
 223                         }
 224                 }
 225                 return copy;
 226         }
 227 }
 228 
 229 static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
 230 {
 231         Bucket *p, *q, *end;
 232         zend_ulong nIndex;
 233 
 234         ht->nTableSize = source->nTableSize;
 235         ht->nTableMask = source->nTableMask;
 236         ht->nNumUsed = 0;
 237         ht->nNumOfElements = source->nNumOfElements;
 238         ht->nNextFreeElement = source->nNextFreeElement;
 239         ht->pDestructor = ZVAL_PTR_DTOR;
 240         ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
 241         ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
 242 
 243         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
 244                 ht->arData = source->arData;
 245                 return;
 246         }
 247 
 248         ZEND_ASSERT((source->u.flags & HASH_FLAG_PACKED) == 0);
 249         HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
 250         HT_HASH_RESET(ht);
 251 
 252         p = source->arData;
 253         end = p + source->nNumUsed;
 254         for (; p != end; p++) {
 255                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 256                 nIndex = p->h | ht->nTableMask;
 257 
 258                 /* Insert into hash collision list */
 259                 q = ht->arData + ht->nNumUsed;
 260                 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
 261                 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
 262 
 263                 /* Initialize key */
 264                 q->h = p->h;
 265                 q->key = p->key;
 266 
 267                 /* Copy data */
 268                 ZVAL_COPY_VALUE(&q->val, &p->val);
 269                 zend_clone_zval(&q->val);
 270         }
 271 }
 272 
 273 static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
 274 {
 275         Bucket *p, *q, *end;
 276         zend_ulong nIndex;
 277         zend_op_array *new_entry;
 278 
 279         ht->nTableSize = source->nTableSize;
 280         ht->nTableMask = source->nTableMask;
 281         ht->nNumUsed = 0;
 282         ht->nNumOfElements = source->nNumOfElements;
 283         ht->nNextFreeElement = source->nNextFreeElement;
 284         ht->pDestructor = ZEND_FUNCTION_DTOR;
 285         ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
 286         ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
 287 
 288         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
 289                 ht->arData = source->arData;
 290                 return;
 291         }
 292 
 293         ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
 294         HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
 295         HT_HASH_RESET(ht);
 296 
 297         p = source->arData;
 298         end = p + source->nNumUsed;
 299         for (; p != end; p++) {
 300                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 301 
 302                 nIndex = p->h | ht->nTableMask;
 303 
 304                 /* Insert into hash collision list */
 305                 q = ht->arData + ht->nNumUsed;
 306                 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
 307                 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
 308 
 309                 /* Initialize key */
 310                 q->h = p->h;
 311                 ZEND_ASSERT(p->key != NULL);
 312                 q->key = p->key;
 313 
 314                 /* Copy data */
 315                 ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
 316                 new_entry = (zend_op_array*)Z_PTR(q->val);
 317 
 318                 if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem &&
 319                     (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
 320 
 321                         new_entry->scope = ARENA_REALLOC(new_entry->scope);
 322 
 323                         /* update prototype */
 324                         if (new_entry->prototype) {
 325                                 new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
 326                         }
 327                 }
 328         }
 329 }
 330 
 331 static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce)
 332 {
 333         Bucket *p, *q, *end;
 334         zend_ulong nIndex;
 335         zend_property_info *prop_info;
 336 
 337         ht->nTableSize = source->nTableSize;
 338         ht->nTableMask = source->nTableMask;
 339         ht->nNumUsed = 0;
 340         ht->nNumOfElements = source->nNumOfElements;
 341         ht->nNextFreeElement = source->nNextFreeElement;
 342         ht->pDestructor = NULL;
 343         ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
 344         ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
 345 
 346         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
 347                 ht->arData = source->arData;
 348                 return;
 349         }
 350 
 351         ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
 352         HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
 353         HT_HASH_RESET(ht);
 354 
 355         p = source->arData;
 356         end = p + source->nNumUsed;
 357         for (; p != end; p++) {
 358                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 359 
 360                 nIndex = p->h | ht->nTableMask;
 361 
 362                 /* Insert into hash collision list */
 363                 q = ht->arData + ht->nNumUsed;
 364                 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
 365                 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
 366 
 367                 /* Initialize key */
 368                 q->h = p->h;
 369                 ZEND_ASSERT(p->key != NULL);
 370                 q->key = p->key;
 371 
 372                 /* Copy data */
 373                 prop_info = ARENA_REALLOC(Z_PTR(p->val));
 374                 ZVAL_PTR(&q->val, prop_info);
 375 
 376                 if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem &&
 377                     (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
 378                         prop_info->ce = ARENA_REALLOC(prop_info->ce);
 379                 }
 380         }
 381 }
 382 
 383 #define zend_update_inherited_handler(handler) \
 384 { \
 385         if (ce->handler != NULL) { \
 386                 ce->handler = ARENA_REALLOC(ce->handler); \
 387         } \
 388 }
 389 
 390 /* Protects class' refcount, copies default properties, functions and class name */
 391 static void zend_class_copy_ctor(zend_class_entry **pce)
 392 {
 393         zend_class_entry *ce = *pce;
 394         zend_class_entry *old_ce = ce;
 395         zval *src, *dst, *end;
 396 
 397         *pce = ce = ARENA_REALLOC(old_ce);
 398         ce->refcount = 1;
 399 
 400         if (old_ce->default_properties_table) {
 401                 ce->default_properties_table = emalloc(sizeof(zval) * old_ce->default_properties_count);
 402                 src = old_ce->default_properties_table;
 403                 end = src + old_ce->default_properties_count;
 404                 dst = ce->default_properties_table;
 405                 for (; src != end; src++, dst++) {
 406                         ZVAL_COPY_VALUE(dst, src);
 407                         zend_clone_zval(dst);
 408                 }
 409         }
 410 
 411         zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce);
 412 
 413         /* static members */
 414         if (old_ce->default_static_members_table) {
 415                 ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count);
 416                 src = old_ce->default_static_members_table;
 417                 end = src + old_ce->default_static_members_count;
 418                 dst = ce->default_static_members_table;
 419                 for (; src != end; src++, dst++) {
 420                         ZVAL_COPY_VALUE(dst, src);
 421                         zend_clone_zval(dst);
 422                 }
 423         }
 424         ce->static_members_table = ce->default_static_members_table;
 425 
 426         /* properties_info */
 427         zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce);
 428 
 429         /* constants table */
 430         zend_hash_clone_constants(&ce->constants_table, &old_ce->constants_table);
 431         ce->constants_table.u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
 432 
 433         /* interfaces aren't really implemented, so we create a new table */
 434         if (ce->num_interfaces) {
 435                 ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
 436                 memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
 437         } else {
 438                 ce->interfaces = NULL;
 439         }
 440 
 441         if (ce->parent) {
 442                 ce->parent = ARENA_REALLOC(ce->parent);
 443         }
 444 
 445         zend_update_inherited_handler(constructor);
 446         zend_update_inherited_handler(destructor);
 447         zend_update_inherited_handler(clone);
 448         zend_update_inherited_handler(__get);
 449         zend_update_inherited_handler(__set);
 450         zend_update_inherited_handler(__call);
 451 /* 5.1 stuff */
 452         zend_update_inherited_handler(serialize_func);
 453         zend_update_inherited_handler(unserialize_func);
 454         zend_update_inherited_handler(__isset);
 455         zend_update_inherited_handler(__unset);
 456 /* 5.2 stuff */
 457         zend_update_inherited_handler(__tostring);
 458 
 459 /* 5.3 stuff */
 460         zend_update_inherited_handler(__callstatic);
 461         zend_update_inherited_handler(__debugInfo);
 462 
 463 /* 5.4 traits */
 464         if (ce->trait_aliases) {
 465                 zend_trait_alias **trait_aliases;
 466                 int i = 0;
 467 
 468                 while (ce->trait_aliases[i]) {
 469                         i++;
 470                 }
 471                 trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
 472                 i = 0;
 473                 while (ce->trait_aliases[i]) {
 474                         trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
 475                         memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
 476                         trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
 477                         memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
 478                         i++;
 479                 }
 480                 trait_aliases[i] = NULL;
 481                 ce->trait_aliases = trait_aliases;
 482         }
 483 
 484         if (ce->trait_precedences) {
 485                 zend_trait_precedence **trait_precedences;
 486                 int i = 0;
 487 
 488                 while (ce->trait_precedences[i]) {
 489                         i++;
 490                 }
 491                 trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
 492                 i = 0;
 493                 while (ce->trait_precedences[i]) {
 494                         trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
 495                         memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
 496                         trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
 497                         memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
 498 
 499                         if (trait_precedences[i]->exclude_from_classes) {
 500                                 zend_string **exclude_from_classes;
 501                                 int j = 0;
 502 
 503                                 while (trait_precedences[i]->exclude_from_classes[j].class_name) {
 504                                         j++;
 505                                 }
 506                                 exclude_from_classes = emalloc(sizeof(zend_string*) * (j + 1));
 507                                 j = 0;
 508                                 while (trait_precedences[i]->exclude_from_classes[j].class_name) {
 509                                         exclude_from_classes[j] =
 510                                                 trait_precedences[i]->exclude_from_classes[j].class_name;
 511                                         j++;
 512                                 }
 513                                 exclude_from_classes[j] = NULL;
 514                                 trait_precedences[i]->exclude_from_classes = (void*)exclude_from_classes;
 515                         }
 516                         i++;
 517                 }
 518                 trait_precedences[i] = NULL;
 519                 ce->trait_precedences = trait_precedences;
 520         }
 521 }
 522 
 523 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
 524 {
 525         zend_function *function1, *function2;
 526         Bucket *p, *end;
 527         zval *t;
 528 
 529         zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
 530         p = source->arData;
 531         end = p + source->nNumUsed;
 532         for (; p != end; p++) {
 533                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 534                 ZEND_ASSERT(p->key);
 535                 t = zend_hash_find(target, p->key);
 536                 if (UNEXPECTED(t != NULL)) {
 537                         if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
 538                                 /* Mangled key */
 539                                 t = zend_hash_update(target, p->key, &p->val);
 540                         } else {
 541                                 goto failure;
 542                         }
 543                 } else {
 544                         _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
 545                 }
 546         }
 547         target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
 548         return;
 549 
 550 failure:
 551         function1 = Z_PTR(p->val);
 552         function2 = Z_PTR_P(t);
 553         CG(in_compilation) = 1;
 554         zend_set_compiled_filename(function1->op_array.filename);
 555         CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
 556         if (function2->type == ZEND_USER_FUNCTION
 557                 && function2->op_array.last > 0) {
 558                 zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
 559                                    ZSTR_VAL(function1->common.function_name),
 560                                    ZSTR_VAL(function2->op_array.filename),
 561                                    (int)function2->op_array.opcodes[0].lineno);
 562         } else {
 563                 zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
 564         }
 565 }
 566 
 567 static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source)
 568 {
 569         zend_function *function1, *function2;
 570         Bucket *p, *end;
 571         zval *t;
 572 
 573         zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
 574         p = source->arData;
 575         end = p + source->nNumUsed;
 576         for (; p != end; p++) {
 577                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 578                 ZEND_ASSERT(p->key);
 579                 t = zend_hash_find(target, p->key);
 580                 if (UNEXPECTED(t != NULL)) {
 581                         if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
 582                                 /* Mangled key */
 583                                 zend_hash_update_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
 584                         } else {
 585                                 goto failure;
 586                         }
 587                 } else {
 588                         _zend_hash_append_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
 589                 }
 590         }
 591         target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
 592         return;
 593 
 594 failure:
 595         function1 = Z_PTR(p->val);
 596         function2 = Z_PTR_P(t);
 597         CG(in_compilation) = 1;
 598         zend_set_compiled_filename(function1->op_array.filename);
 599         CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
 600         if (function2->type == ZEND_USER_FUNCTION
 601                 && function2->op_array.last > 0) {
 602                 zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
 603                                    ZSTR_VAL(function1->common.function_name),
 604                                    ZSTR_VAL(function2->op_array.filename),
 605                                    (int)function2->op_array.opcodes[0].lineno);
 606         } else {
 607                 zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
 608         }
 609 }
 610 
 611 static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
 612 {
 613         zend_class_entry *ce1;
 614         Bucket *p, *end;
 615         zval *t;
 616 
 617         zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
 618         p = source->arData;
 619         end = p + source->nNumUsed;
 620         for (; p != end; p++) {
 621                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 622                 ZEND_ASSERT(p->key);
 623                 t = zend_hash_find(target, p->key);
 624                 if (UNEXPECTED(t != NULL)) {
 625                         if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
 626                                 /* Mangled key - ignore and wait for runtime */
 627                                 continue;
 628                         } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
 629                                 goto failure;
 630                         }
 631                 } else {
 632                         t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
 633                         if (pCopyConstructor) {
 634                                 pCopyConstructor(&Z_PTR_P(t));
 635                         }
 636                 }
 637         }
 638         target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
 639         return;
 640 
 641 failure:
 642         ce1 = Z_PTR(p->val);
 643         CG(in_compilation) = 1;
 644         zend_set_compiled_filename(ce1->info.user.filename);
 645         CG(zend_lineno) = ce1->info.user.line_start;
 646         zend_error(E_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
 647 }
 648 
 649 #ifdef __SSE2__
 650 #include <mmintrin.h>
 651 #include <emmintrin.h>
 652 
 653 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
 654 {
 655         __m128i *dqdest = (__m128i*)dest;
 656         const __m128i *dqsrc  = (const __m128i*)src;
 657         const __m128i *end  = (const __m128i*)((const char*)src + size);
 658 
 659         do {
 660                 _mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
 661                 _mm_prefetch(dqdest + 4, _MM_HINT_T0);
 662 
 663                 __m128i xmm0 = _mm_load_si128(dqsrc + 0);
 664                 __m128i xmm1 = _mm_load_si128(dqsrc + 1);
 665                 __m128i xmm2 = _mm_load_si128(dqsrc + 2);
 666                 __m128i xmm3 = _mm_load_si128(dqsrc + 3);
 667                 dqsrc  += 4;
 668                 _mm_store_si128(dqdest + 0, xmm0);
 669                 _mm_store_si128(dqdest + 1, xmm1);
 670                 _mm_store_si128(dqdest + 2, xmm2);
 671                 _mm_store_si128(dqdest + 3, xmm3);
 672                 dqdest += 4;
 673         } while (dqsrc != end);
 674 }
 675 #endif
 676 
 677 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
 678 {
 679         zend_op_array *op_array;
 680 
 681         op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
 682         *op_array = persistent_script->main_op_array;
 683 
 684         if (EXPECTED(from_shared_memory)) {
 685                 zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
 686 
 687                 ZCG(current_persistent_script) = persistent_script;
 688                 ZCG(arena_mem) = NULL;
 689                 if (EXPECTED(persistent_script->arena_size)) {
 690 #ifdef __SSE2__
 691                         /* Target address must be aligned to 64-byte boundary */
 692                         ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
 693                         ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
 694                         fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
 695 #else
 696                         ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
 697                         memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
 698 #endif
 699                 }
 700 
 701                 /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
 702                 if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
 703                         zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, (unique_copy_ctor_func_t) zend_class_copy_ctor);
 704                 }
 705                 /* we must first to copy all classes and then prepare functions, since functions may try to bind
 706                    classes - which depend on pre-bind class entries existent in the class table */
 707                 if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
 708                         zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->function_table);
 709                 }
 710 
 711                 /* Register __COMPILER_HALT_OFFSET__ constant */
 712                 if (persistent_script->compiler_halt_offset != 0 &&
 713                     persistent_script->full_path) {
 714                         zend_string *name;
 715                         char haltoff[] = "__COMPILER_HALT_OFFSET__";
 716 
 717                         name = zend_mangle_property_name(haltoff, sizeof(haltoff) - 1, ZSTR_VAL(persistent_script->full_path), ZSTR_LEN(persistent_script->full_path), 0);
 718                         if (!zend_hash_exists(EG(zend_constants), name)) {
 719                                 zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), persistent_script->compiler_halt_offset, CONST_CS, 0);
 720                         }
 721                         zend_string_release(name);
 722                 }
 723 
 724                 zend_hash_destroy(&ZCG(bind_hash));
 725                 ZCG(current_persistent_script) = NULL;
 726         } else /* if (!from_shared_memory) */ {
 727                 if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
 728                         zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table);
 729                 }
 730                 if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
 731                         zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, NULL);
 732                 }
 733         }
 734 
 735         if (op_array->early_binding != (uint32_t)-1) {
 736                 zend_string *orig_compiled_filename = CG(compiled_filename);
 737                 CG(compiled_filename) = persistent_script->full_path;
 738                 zend_do_delayed_early_binding(op_array);
 739                 CG(compiled_filename) = orig_compiled_filename;
 740         }
 741 
 742         if (UNEXPECTED(!from_shared_memory)) {
 743                 free_persistent_script(persistent_script, 0); /* free only hashes */
 744         }
 745 
 746         return op_array;
 747 }
 748 
 749 /*
 750  * zend_adler32() is based on zlib implementation
 751  * Computes the Adler-32 checksum of a data stream
 752  *
 753  * Copyright (C) 1995-2005 Mark Adler
 754  * For conditions of distribution and use, see copyright notice in zlib.h
 755  *
 756  * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
 757  *
 758  *  This software is provided 'as-is', without any express or implied
 759  *  warranty.  In no event will the authors be held liable for any damages
 760  *  arising from the use of this software.
 761  *
 762  *  Permission is granted to anyone to use this software for any purpose,
 763  *  including commercial applications, and to alter it and redistribute it
 764  *  freely, subject to the following restrictions:
 765  *
 766  *  1. The origin of this software must not be misrepresented; you must not
 767  *     claim that you wrote the original software. If you use this software
 768  *     in a product, an acknowledgment in the product documentation would be
 769  *     appreciated but is not required.
 770  *  2. Altered source versions must be plainly marked as such, and must not be
 771  *     misrepresented as being the original software.
 772  *  3. This notice may not be removed or altered from any source distribution.
 773  *
 774  */
 775 
 776 #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
 777 #define ADLER32_NMAX 5552
 778 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
 779 
 780 #define ADLER32_DO1(buf)        {s1 += *(buf); s2 += s1;}
 781 #define ADLER32_DO2(buf, i)     ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
 782 #define ADLER32_DO4(buf, i)     ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
 783 #define ADLER32_DO8(buf, i)     ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
 784 #define ADLER32_DO16(buf)       ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
 785 
 786 unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len)
 787 {
 788         unsigned int s1 = checksum & 0xffff;
 789         unsigned int s2 = (checksum >> 16) & 0xffff;
 790         signed char *end;
 791 
 792         while (len >= ADLER32_NMAX) {
 793                 len -= ADLER32_NMAX;
 794                 end = buf + ADLER32_NMAX;
 795                 do {
 796                         ADLER32_DO16(buf);
 797                         buf += 16;
 798                 } while (buf != end);
 799                 s1 %= ADLER32_BASE;
 800                 s2 %= ADLER32_BASE;
 801         }
 802 
 803         if (len) {
 804                 if (len >= 16) {
 805                         end = buf + (len & 0xfff0);
 806                         len &= 0xf;
 807                         do {
 808                                 ADLER32_DO16(buf);
 809                                 buf += 16;
 810                         } while (buf != end);
 811                 }
 812                 if (len) {
 813                         end = buf + len;
 814                         do {
 815                                 ADLER32_DO1(buf);
 816                                 buf++;
 817                         } while (buf != end);
 818                 }
 819                 s1 %= ADLER32_BASE;
 820                 s2 %= ADLER32_BASE;
 821         }
 822 
 823         return (s2 << 16) | s1;
 824 }
 825 
 826 unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
 827 {
 828         signed char *mem = (signed char*)persistent_script->mem;
 829         size_t size = persistent_script->size;
 830         size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
 831         unsigned int checksum = ADLER32_INIT;
 832 
 833         if (mem < (signed char*)persistent_script) {
 834                 checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
 835                 size -= (signed char*)persistent_script - mem;
 836                 mem  += (signed char*)persistent_script - mem;
 837         }
 838 
 839         zend_adler32(checksum, mem, persistent_script_check_block_size);
 840         mem  += sizeof(*persistent_script);
 841         size -= sizeof(*persistent_script);
 842 
 843         if (size > 0) {
 844                 checksum = zend_adler32(checksum, mem, size);
 845         }
 846         return checksum;
 847 }

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