root/Zend/zend_string.c

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

DEFINITIONS

This source file includes following definitions.
  1. zend_hash_func
  2. _str_dtor
  3. zend_interned_strings_init
  4. zend_interned_strings_dtor
  5. zend_new_interned_string_int
  6. zend_interned_strings_snapshot_int
  7. zend_interned_strings_restore_int

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt.                                |
  11    | If you did not receive a copy of the Zend license and are unable to  |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@zend.com so we can mail you a copy immediately.              |
  14    +----------------------------------------------------------------------+
  15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id: $ */
  20 
  21 #include "zend.h"
  22 #include "zend_globals.h"
  23 
  24 ZEND_API zend_string *(*zend_new_interned_string)(zend_string *str);
  25 ZEND_API void (*zend_interned_strings_snapshot)(void);
  26 ZEND_API void (*zend_interned_strings_restore)(void);
  27 
  28 static zend_string *zend_new_interned_string_int(zend_string *str);
  29 static void zend_interned_strings_snapshot_int(void);
  30 static void zend_interned_strings_restore_int(void);
  31 
  32 ZEND_API zend_ulong zend_hash_func(const char *str, size_t len)
  33 {
  34         return zend_inline_hash_func(str, len);
  35 }
  36 
  37 #ifndef ZTS
  38 static void _str_dtor(zval *zv)
  39 {
  40         zend_string *str = Z_STR_P(zv);
  41         pefree(str, GC_FLAGS(str) & IS_STR_PERSISTENT);
  42 }
  43 #endif
  44 
  45 void zend_interned_strings_init(void)
  46 {
  47 #ifndef ZTS
  48         zend_string *str;
  49 
  50         zend_hash_init(&CG(interned_strings), 1024, NULL, _str_dtor, 1);
  51 
  52         CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
  53         HT_SET_DATA_ADDR(&CG(interned_strings), pemalloc(HT_SIZE(&CG(interned_strings)), 1));
  54         HT_HASH_RESET(&CG(interned_strings));
  55         CG(interned_strings).u.flags |= HASH_FLAG_INITIALIZED;
  56 
  57         /* interned empty string */
  58         str = zend_string_alloc(sizeof("")-1, 1);
  59         ZSTR_VAL(str)[0] = '\000';
  60         CG(empty_string) = zend_new_interned_string_int(str);
  61 #endif
  62 
  63         /* one char strings (the actual interned strings are going to be created by ext/opcache) */
  64         memset(CG(one_char_string), 0, sizeof(CG(one_char_string)));
  65 
  66         zend_new_interned_string = zend_new_interned_string_int;
  67         zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
  68         zend_interned_strings_restore = zend_interned_strings_restore_int;
  69 }
  70 
  71 void zend_interned_strings_dtor(void)
  72 {
  73 #ifndef ZTS
  74         zend_hash_destroy(&CG(interned_strings));
  75 #endif
  76 }
  77 
  78 static zend_string *zend_new_interned_string_int(zend_string *str)
  79 {
  80 #ifndef ZTS
  81         zend_ulong h;
  82         uint nIndex;
  83         uint idx;
  84         Bucket *p;
  85 
  86         if (ZSTR_IS_INTERNED(str)) {
  87                 return str;
  88         }
  89 
  90         h = zend_string_hash_val(str);
  91         nIndex = h | CG(interned_strings).nTableMask;
  92         idx = HT_HASH(&CG(interned_strings), nIndex);
  93         while (idx != HT_INVALID_IDX) {
  94                 p = HT_HASH_TO_BUCKET(&CG(interned_strings), idx);
  95                 if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
  96                         if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
  97                                 zend_string_release(str);
  98                                 return p->key;
  99                         }
 100                 }
 101                 idx = Z_NEXT(p->val);
 102         }
 103 
 104         GC_REFCOUNT(str) = 1;
 105         GC_FLAGS(str) |= IS_STR_INTERNED;
 106 
 107         if (CG(interned_strings).nNumUsed >= CG(interned_strings).nTableSize) {
 108                 if (CG(interned_strings).nTableSize < HT_MAX_SIZE) {    /* Let's double the table size */
 109                         void *new_data;
 110                         void *old_data = HT_GET_DATA_ADDR(&CG(interned_strings));
 111                         Bucket *old_buckets = CG(interned_strings).arData;
 112 
 113                         HANDLE_BLOCK_INTERRUPTIONS();
 114                         CG(interned_strings).nTableSize += CG(interned_strings).nTableSize;
 115                         CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
 116                         new_data = malloc(HT_SIZE(&CG(interned_strings)));
 117 
 118                         if (new_data) {
 119                                 HT_SET_DATA_ADDR(&CG(interned_strings), new_data);
 120                                 memcpy(CG(interned_strings).arData, old_buckets, sizeof(Bucket) * CG(interned_strings).nNumUsed);
 121                                 free(old_data);
 122                                 zend_hash_rehash(&CG(interned_strings));
 123                         } else {
 124                                 CG(interned_strings).nTableSize = CG(interned_strings).nTableSize >> 1;
 125                                 CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
 126                         }
 127                         HANDLE_UNBLOCK_INTERRUPTIONS();
 128                 }
 129         }
 130 
 131         HANDLE_BLOCK_INTERRUPTIONS();
 132 
 133         idx = CG(interned_strings).nNumUsed++;
 134         CG(interned_strings).nNumOfElements++;
 135         p = CG(interned_strings).arData + idx;
 136         p->h = h;
 137         p->key = str;
 138         Z_STR(p->val) = str;
 139         Z_TYPE_INFO(p->val) = IS_INTERNED_STRING_EX;
 140         nIndex = h | CG(interned_strings).nTableMask;
 141         Z_NEXT(p->val) = HT_HASH(&CG(interned_strings), nIndex);
 142         HT_HASH(&CG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx);
 143 
 144         HANDLE_UNBLOCK_INTERRUPTIONS();
 145 
 146         return str;
 147 #else
 148         return str;
 149 #endif
 150 }
 151 
 152 static void zend_interned_strings_snapshot_int(void)
 153 {
 154 #ifndef ZTS
 155         uint idx;
 156         Bucket *p;
 157 
 158         idx = CG(interned_strings).nNumUsed;
 159         while (idx > 0) {
 160                 idx--;
 161                 p = CG(interned_strings).arData + idx;
 162                 ZEND_ASSERT(GC_FLAGS(p->key) & IS_STR_PERSISTENT);
 163                 GC_FLAGS(p->key) |= IS_STR_PERMANENT;
 164         }
 165 #endif
 166 }
 167 
 168 static void zend_interned_strings_restore_int(void)
 169 {
 170 #ifndef ZTS
 171         uint nIndex;
 172         uint idx;
 173         Bucket *p;
 174 
 175         idx = CG(interned_strings).nNumUsed;
 176         while (idx > 0) {
 177                 idx--;
 178                 p = CG(interned_strings).arData + idx;
 179                 if (GC_FLAGS(p->key) & IS_STR_PERMANENT) break;
 180                 CG(interned_strings).nNumUsed--;
 181                 CG(interned_strings).nNumOfElements--;
 182 
 183                 GC_FLAGS(p->key) &= ~IS_STR_INTERNED;
 184                 GC_REFCOUNT(p->key) = 1;
 185                 zend_string_free(p->key);
 186 
 187                 nIndex = p->h | CG(interned_strings).nTableMask;
 188                 if (HT_HASH(&CG(interned_strings), nIndex) == HT_IDX_TO_HASH(idx)) {
 189                         HT_HASH(&CG(interned_strings), nIndex) = Z_NEXT(p->val);
 190                 } else {
 191                         uint32_t prev = HT_HASH(&CG(interned_strings), nIndex);
 192                         while (Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) != idx) {
 193                                 prev = Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val);
 194                         }
 195                         Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) = Z_NEXT(p->val);
 196                 }
 197         }
 198 #endif
 199 }
 200 
 201 /*
 202  * Local variables:
 203  * tab-width: 4
 204  * c-basic-offset: 4
 205  * indent-tabs-mode: t
 206  * End:
 207  */

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