root/ext/opcache/zend_persist_calc.c

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

DEFINITIONS

This source file includes following definitions.
  1. zend_hash_persist_calc
  2. zend_persist_ast_calc
  3. zend_persist_zval_calc
  4. zend_persist_op_array_calc_ex
  5. zend_persist_op_array_calc
  6. zend_persist_property_info_calc
  7. zend_persist_class_entry_calc
  8. zend_accel_persist_class_table_calc
  9. zend_accel_script_persist_calc

   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_operators.h"
  28 
  29 #define ADD_DUP_SIZE(m,s)  ZCG(current_persistent_script)->size += zend_shared_memdup_size((void*)m, s)
  30 #define ADD_SIZE(m)        ZCG(current_persistent_script)->size += ZEND_ALIGNED_SIZE(m)
  31 
  32 #define ADD_ARENA_SIZE(m)        ZCG(current_persistent_script)->arena_size += ZEND_ALIGNED_SIZE(m)
  33 
  34 # define ADD_STRING(str) ADD_DUP_SIZE((str), _ZSTR_STRUCT_SIZE(ZSTR_LEN(str)))
  35 
  36 # define ADD_INTERNED_STRING(str, do_free) do { \
  37                 if (ZCG(current_persistent_script)->corrupted) { \
  38                         ADD_STRING(str); \
  39                 } else if (!IS_ACCEL_INTERNED(str)) { \
  40                         zend_string *tmp = accel_new_interned_string(str); \
  41                         if (tmp != (str)) { \
  42                                 if (do_free) { \
  43                                         /*zend_string_release(str);*/ \
  44                                 } \
  45                                 (str) = tmp; \
  46                         } else { \
  47                                 ADD_STRING(str); \
  48                         } \
  49                 } \
  50         } while (0)
  51 
  52 static void zend_persist_zval_calc(zval *z);
  53 
  54 static void zend_hash_persist_calc(HashTable *ht, void (*pPersistElement)(zval *pElement))
  55 {
  56         uint idx;
  57         Bucket *p;
  58 
  59         if (!(ht->u.flags & HASH_FLAG_INITIALIZED) || ht->nNumUsed == 0) {
  60                 return;
  61         }
  62 
  63         if (!(ht->u.flags & HASH_FLAG_PACKED) && ht->nNumUsed < -(int32_t)ht->nTableMask / 2) {
  64                 /* compact table */
  65                 int32_t hash_size;
  66 
  67                 if (ht->nNumUsed <= HT_MIN_SIZE) {
  68                         hash_size = HT_MIN_SIZE;
  69                 } else {
  70                         hash_size = -(int32_t)ht->nTableMask;
  71                         while (hash_size >> 1 > ht->nNumUsed) {
  72                                 hash_size >>= 1;
  73                         }
  74                 }
  75                 ADD_SIZE(hash_size * sizeof(uint32_t) + ht->nNumUsed * sizeof(Bucket));
  76         } else {
  77                 ADD_SIZE(HT_USED_SIZE(ht));
  78         }
  79 
  80         for (idx = 0; idx < ht->nNumUsed; idx++) {
  81                 p = ht->arData + idx;
  82                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
  83 
  84                 /* persist bucket and key */
  85                 if (p->key) {
  86                         zend_uchar flags = GC_FLAGS(p->key) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT);
  87                         ADD_INTERNED_STRING(p->key, 1);
  88                         GC_FLAGS(p->key) |= flags;
  89                 }
  90 
  91                 pPersistElement(&p->val);
  92         }
  93 }
  94 
  95 static void zend_persist_ast_calc(zend_ast *ast)
  96 {
  97         uint32_t i;
  98 
  99         if (ast->kind == ZEND_AST_ZVAL) {
 100                 ADD_SIZE(sizeof(zend_ast_zval));
 101                 zend_persist_zval_calc(zend_ast_get_zval(ast));
 102         } else if (zend_ast_is_list(ast)) {
 103                 zend_ast_list *list = zend_ast_get_list(ast);
 104                 ADD_SIZE(sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
 105                 for (i = 0; i < list->children; i++) {
 106                         if (list->child[i]) {
 107                                 zend_persist_ast_calc(list->child[i]);
 108                         }
 109                 }
 110         } else {
 111                 uint32_t children = zend_ast_get_num_children(ast);
 112                 ADD_SIZE(sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children);
 113                 for (i = 0; i < children; i++) {
 114                         if (ast->child[i]) {
 115                                 zend_persist_ast_calc(ast->child[i]);
 116                         }
 117                 }
 118         }
 119 }
 120 
 121 static void zend_persist_zval_calc(zval *z)
 122 {
 123         zend_uchar flags;
 124         uint size;
 125 
 126         switch (Z_TYPE_P(z)) {
 127                 case IS_STRING:
 128                 case IS_CONSTANT:
 129                         flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT);
 130                         ADD_INTERNED_STRING(Z_STR_P(z), 0);
 131                         if (ZSTR_IS_INTERNED(Z_STR_P(z))) {
 132                                 Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
 133                         }
 134                         Z_GC_FLAGS_P(z) |= flags;
 135                         break;
 136                 case IS_ARRAY:
 137                         size = zend_shared_memdup_size(Z_ARR_P(z), sizeof(zend_array));
 138                         if (size) {
 139                                 ADD_SIZE(size);
 140                                 zend_hash_persist_calc(Z_ARRVAL_P(z), zend_persist_zval_calc);
 141                         }
 142                         break;
 143                 case IS_REFERENCE:
 144                         size = zend_shared_memdup_size(Z_REF_P(z), sizeof(zend_reference));
 145                         if (size) {
 146                                 ADD_SIZE(size);
 147                                 zend_persist_zval_calc(Z_REFVAL_P(z));
 148                         }
 149                         break;
 150                 case IS_CONSTANT_AST:
 151                         size = zend_shared_memdup_size(Z_AST_P(z), sizeof(zend_ast_ref));
 152                         if (size) {
 153                                 ADD_SIZE(size);
 154                                 zend_persist_ast_calc(Z_ASTVAL_P(z));
 155                         }
 156                         break;
 157         }
 158 }
 159 
 160 static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
 161 {
 162         if (op_array->type != ZEND_USER_FUNCTION) {
 163                 return;
 164         }
 165 
 166         if (op_array->static_variables) {
 167                 if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
 168                         HashTable *old = op_array->static_variables;
 169 
 170                         ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
 171                         zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
 172                         zend_shared_alloc_register_xlat_entry(old, op_array->static_variables);
 173                 }
 174         }
 175 
 176         if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
 177                 /* already stored */
 178                 if (op_array->function_name) {
 179                         zend_string *new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
 180                         if (IS_ACCEL_INTERNED(new_name)) {
 181                                 op_array->function_name = new_name;
 182                         }
 183                 }
 184                 return;
 185         }
 186 
 187         if (op_array->literals) {
 188                 zval *p = op_array->literals;
 189                 zval *end = p + op_array->last_literal;
 190                 ADD_DUP_SIZE(op_array->literals, sizeof(zval) * op_array->last_literal);
 191                 while (p < end) {
 192                         zend_persist_zval_calc(p);
 193                         p++;
 194                 }
 195         }
 196 
 197         ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last);
 198 
 199         if (op_array->function_name) {
 200                 zend_string *old_name = op_array->function_name;
 201                 zend_string *new_name = zend_shared_alloc_get_xlat_entry(old_name);
 202 
 203                 if (new_name) {
 204                         op_array->function_name = new_name;
 205                 } else {
 206                         ADD_INTERNED_STRING(op_array->function_name, 0);
 207                         zend_shared_alloc_register_xlat_entry(old_name, op_array->function_name);
 208                 }
 209     }
 210 
 211         if (op_array->filename) {
 212                 ADD_STRING(op_array->filename);
 213         }
 214 
 215         if (op_array->arg_info) {
 216                 zend_arg_info *arg_info = op_array->arg_info;
 217                 uint32_t num_args = op_array->num_args;
 218                 uint32_t i;
 219 
 220                 num_args = op_array->num_args;
 221                 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
 222                         num_args++;
 223                 }
 224                 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
 225                         arg_info--;
 226                         num_args++;
 227                 }
 228                 ADD_DUP_SIZE(arg_info, sizeof(zend_arg_info) * num_args);
 229                 for (i = 0; i < num_args; i++) {
 230                         if (arg_info[i].name) {
 231                                 ADD_INTERNED_STRING(arg_info[i].name, 1);
 232                         }
 233                         if (arg_info[i].class_name) {
 234                                 ADD_INTERNED_STRING(arg_info[i].class_name, 1);
 235                         }
 236                 }
 237         }
 238 
 239         if (op_array->brk_cont_array) {
 240                 ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
 241         }
 242 
 243         if (ZCG(accel_directives).save_comments && op_array->doc_comment) {
 244                 ADD_STRING(op_array->doc_comment);
 245         }
 246 
 247         if (op_array->try_catch_array) {
 248                 ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
 249         }
 250 
 251         if (op_array->vars) {
 252                 int i;
 253 
 254                 ADD_DUP_SIZE(op_array->vars, sizeof(zend_string*) * op_array->last_var);
 255                 for (i = 0; i < op_array->last_var; i++) {
 256                         ADD_INTERNED_STRING(op_array->vars[i], 0);
 257                 }
 258         }
 259 
 260         ADD_SIZE(ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist_calc(op_array)));
 261 }
 262 
 263 static void zend_persist_op_array_calc(zval *zv)
 264 {
 265         zend_op_array *op_array = Z_PTR_P(zv);
 266 
 267         if (op_array->type == ZEND_USER_FUNCTION/* &&
 268             (!op_array->refcount || *(op_array->refcount) > 1)*/) {
 269                 zend_op_array *old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
 270                 if (old_op_array) {
 271                         Z_PTR_P(zv) = old_op_array;
 272                 } else {
 273                         ADD_ARENA_SIZE(sizeof(zend_op_array));
 274                         zend_persist_op_array_calc_ex(Z_PTR_P(zv));
 275                         zend_shared_alloc_register_xlat_entry(op_array, Z_PTR_P(zv));
 276                 }
 277         } else {
 278                 ADD_ARENA_SIZE(sizeof(zend_op_array));
 279                 zend_persist_op_array_calc_ex(Z_PTR_P(zv));
 280         }
 281 }
 282 
 283 static void zend_persist_property_info_calc(zval *zv)
 284 {
 285         zend_property_info *prop = Z_PTR_P(zv);
 286 
 287         if (!zend_shared_alloc_get_xlat_entry(prop)) {
 288                 zend_shared_alloc_register_xlat_entry(prop, prop);
 289                 ADD_ARENA_SIZE(sizeof(zend_property_info));
 290                 ADD_INTERNED_STRING(prop->name, 0);
 291                 if (ZCG(accel_directives).save_comments && prop->doc_comment) {
 292                         ADD_STRING(prop->doc_comment);
 293                 }
 294         }
 295 }
 296 
 297 static void zend_persist_class_entry_calc(zval *zv)
 298 {
 299         zend_class_entry *ce = Z_PTR_P(zv);
 300 
 301         if (ce->type == ZEND_USER_CLASS) {
 302                 ADD_ARENA_SIZE(sizeof(zend_class_entry));
 303                 ADD_INTERNED_STRING(ce->name, 0);
 304                 zend_hash_persist_calc(&ce->function_table, zend_persist_op_array_calc);
 305                 if (ce->default_properties_table) {
 306                     int i;
 307 
 308                         ADD_SIZE(sizeof(zval) * ce->default_properties_count);
 309                         for (i = 0; i < ce->default_properties_count; i++) {
 310                                 zend_persist_zval_calc(&ce->default_properties_table[i]);
 311                         }
 312                 }
 313                 if (ce->default_static_members_table) {
 314                     int i;
 315 
 316                         ADD_SIZE(sizeof(zval) * ce->default_static_members_count);
 317                         for (i = 0; i < ce->default_static_members_count; i++) {
 318                                 zend_persist_zval_calc(&ce->default_static_members_table[i]);
 319                         }
 320                 }
 321                 zend_hash_persist_calc(&ce->constants_table, zend_persist_zval_calc);
 322 
 323                 if (ZEND_CE_FILENAME(ce)) {
 324                         ADD_STRING(ZEND_CE_FILENAME(ce));
 325                 }
 326                 if (ZCG(accel_directives).save_comments && ZEND_CE_DOC_COMMENT(ce)) {
 327                         ADD_STRING(ZEND_CE_DOC_COMMENT(ce));
 328                 }
 329 
 330                 zend_hash_persist_calc(&ce->properties_info, zend_persist_property_info_calc);
 331 
 332                 if (ce->trait_aliases) {
 333                         int i = 0;
 334                         while (ce->trait_aliases[i]) {
 335                                 if (ce->trait_aliases[i]->trait_method) {
 336                                         if (ce->trait_aliases[i]->trait_method->method_name) {
 337                                                 ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method->method_name, 0);
 338                                         }
 339                                         if (ce->trait_aliases[i]->trait_method->class_name) {
 340                                                 ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method->class_name, 0);
 341                                         }
 342                                         ADD_SIZE(sizeof(zend_trait_method_reference));
 343                                 }
 344 
 345                                 if (ce->trait_aliases[i]->alias) {
 346                                         ADD_INTERNED_STRING(ce->trait_aliases[i]->alias, 0);
 347                                 }
 348                                 ADD_SIZE(sizeof(zend_trait_alias));
 349                                 i++;
 350                         }
 351                         ADD_SIZE(sizeof(zend_trait_alias*) * (i + 1));
 352                 }
 353 
 354                 if (ce->trait_precedences) {
 355                         int i = 0;
 356 
 357                         while (ce->trait_precedences[i]) {
 358                                 ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method->method_name, 0);
 359                                 ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method->class_name, 0);
 360                                 ADD_SIZE(sizeof(zend_trait_method_reference));
 361 
 362                                 if (ce->trait_precedences[i]->exclude_from_classes) {
 363                                         int j = 0;
 364 
 365                                         while (ce->trait_precedences[i]->exclude_from_classes[j].class_name) {
 366                                                 ADD_INTERNED_STRING(ce->trait_precedences[i]->exclude_from_classes[j].class_name, 0);
 367                                                 j++;
 368                                         }
 369                                         ADD_SIZE(sizeof(zend_class_entry*) * (j + 1));
 370                                 }
 371                                 ADD_SIZE(sizeof(zend_trait_precedence));
 372                                 i++;
 373                         }
 374                         ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1));
 375                 }
 376         }
 377 }
 378 
 379 static void zend_accel_persist_class_table_calc(HashTable *class_table)
 380 {
 381         zend_hash_persist_calc(class_table, zend_persist_class_entry_calc);
 382 }
 383 
 384 uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length)
 385 {
 386         new_persistent_script->mem = NULL;
 387         new_persistent_script->size = 0;
 388         new_persistent_script->arena_mem = NULL;
 389         new_persistent_script->arena_size = 0;
 390         new_persistent_script->corrupted = 0;
 391         ZCG(current_persistent_script) = new_persistent_script;
 392 
 393         ADD_DUP_SIZE(new_persistent_script, sizeof(zend_persistent_script));
 394         if (key) {
 395                 ADD_DUP_SIZE(key, key_length + 1);
 396         } else {
 397                 /* script is not going to be saved in SHM */
 398                 new_persistent_script->corrupted = 1;
 399         }
 400         ADD_STRING(new_persistent_script->full_path);
 401 
 402 #ifdef __SSE2__
 403         /* Align size to 64-byte boundary */
 404         new_persistent_script->size = (new_persistent_script->size + 63) & ~63;
 405 #endif
 406 
 407         zend_accel_persist_class_table_calc(&new_persistent_script->class_table);
 408         zend_hash_persist_calc(&new_persistent_script->function_table, zend_persist_op_array_calc);
 409         zend_persist_op_array_calc_ex(&new_persistent_script->main_op_array);
 410 
 411 #ifdef __SSE2__
 412         /* Align size to 64-byte boundary */
 413         new_persistent_script->arena_size = (new_persistent_script->arena_size + 63) & ~63;
 414 #endif
 415 
 416         new_persistent_script->size += new_persistent_script->arena_size;
 417         new_persistent_script->corrupted = 0;
 418 
 419         ZCG(current_persistent_script) = NULL;
 420 
 421         return new_persistent_script->size;
 422 }

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