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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/Zend - zend_gc.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 360
Code covered: 95.0 % Executed lines: 342
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | Zend Engine                                                          |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1998-2009 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: David Wang <planetbeing@gmail.com>                          |
      16                 :    |          Dmitry Stogov <dmitry@zend.com>                             |
      17                 :    +----------------------------------------------------------------------+
      18                 : */
      19                 : 
      20                 : /* $Id: zend_gc.c 278220 2009-04-03 18:52:21Z dmitry $ */
      21                 : 
      22                 : #include "zend.h"
      23                 : #include "zend_API.h"
      24                 : 
      25                 : #define GC_ROOT_BUFFER_MAX_ENTRIES 10000
      26                 : 
      27                 : #ifdef ZTS
      28                 : ZEND_API int gc_globals_id;
      29                 : #else
      30                 : ZEND_API zend_gc_globals gc_globals;
      31                 : #endif
      32                 : 
      33                 : static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
      34           17665 : {
      35           17665 :         if (gc_globals->buf) {
      36           17664 :                 free(gc_globals->buf);
      37           17664 :                 gc_globals->buf = NULL;
      38                 :         }       
      39           17665 : }
      40                 : 
      41                 : static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
      42           17633 : {
      43           17633 :         gc_globals->gc_enabled = 0;
      44           17633 :         gc_globals->gc_active = 0;
      45                 : 
      46           17633 :         gc_globals->buf = NULL;
      47                 : 
      48           17633 :         gc_globals->roots.next = &gc_globals->roots;
      49           17633 :         gc_globals->roots.prev = &gc_globals->roots;
      50           17633 :         gc_globals->unused = NULL;
      51           17633 :         gc_globals->zval_to_free = NULL;
      52           17633 :         gc_globals->free_list = NULL;
      53           17633 :         gc_globals->next_to_free = NULL;
      54                 : 
      55           17633 :         gc_globals->gc_runs = 0;
      56           17633 :         gc_globals->collected = 0;
      57                 : 
      58                 : #if GC_BENCH
      59                 :         gc_globals->root_buf_length = 0;
      60                 :         gc_globals->root_buf_peak = 0;
      61                 :         gc_globals->zval_possible_root = 0;
      62                 :         gc_globals->zobj_possible_root = 0;
      63                 :         gc_globals->zval_buffered = 0;
      64                 :         gc_globals->zobj_buffered = 0;
      65                 :         gc_globals->zval_remove_from_buffer = 0;
      66                 :         gc_globals->zobj_remove_from_buffer = 0;
      67                 :         gc_globals->zval_marked_grey = 0;
      68                 :         gc_globals->zobj_marked_grey = 0;
      69                 : #endif
      70           17633 : }
      71                 : 
      72                 : ZEND_API void gc_globals_ctor(TSRMLS_D)
      73           17633 : {
      74                 : #ifdef ZTS
      75                 :         ts_allocate_id(&gc_globals_id, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
      76                 : #else
      77           17633 :         gc_globals_ctor_ex(&gc_globals);
      78                 : #endif
      79           17633 : }
      80                 : 
      81                 : ZEND_API void gc_globals_dtor(TSRMLS_D)
      82           17665 : {
      83                 : #ifndef ZTS
      84           17665 :         root_buffer_dtor(&gc_globals TSRMLS_DC);
      85                 : #endif
      86           17665 : }
      87                 : 
      88                 : ZEND_API void gc_reset(TSRMLS_D)
      89           35251 : {
      90           35251 :         GC_G(gc_runs) = 0;
      91           35251 :         GC_G(collected) = 0;
      92                 : 
      93                 : #if GC_BENCH
      94                 :         GC_G(root_buf_length) = 0;
      95                 :         GC_G(root_buf_peak) = 0;
      96                 :         GC_G(zval_possible_root) = 0;
      97                 :         GC_G(zobj_possible_root) = 0;
      98                 :         GC_G(zval_buffered) = 0;
      99                 :         GC_G(zobj_buffered) = 0;
     100                 :         GC_G(zval_remove_from_buffer) = 0;
     101                 :         GC_G(zobj_remove_from_buffer) = 0;
     102                 :         GC_G(zval_marked_grey) = 0;
     103                 :         GC_G(zobj_marked_grey) = 0;
     104                 : #endif
     105                 : 
     106           35251 :         GC_G(roots).next = &GC_G(roots);
     107           35251 :         GC_G(roots).prev = &GC_G(roots);
     108                 : 
     109           35251 :         if (GC_G(buf)) {
     110           35249 :                 GC_G(unused) = NULL;
     111           35249 :                 GC_G(first_unused) = GC_G(buf);
     112                 : 
     113           35249 :                 GC_G(zval_to_free) = NULL;
     114                 :         } else {
     115               2 :                 GC_G(unused) = NULL;
     116               2 :                 GC_G(first_unused) = NULL;
     117               2 :                 GC_G(last_unused) = NULL;
     118                 :         }
     119           35251 : }
     120                 : 
     121                 : ZEND_API void gc_init(TSRMLS_D)
     122           17638 : {
     123           17638 :         if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
     124           17632 :                 GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
     125           17632 :                 GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
     126           17632 :                 gc_reset(TSRMLS_C);
     127                 :         }
     128           17638 : }
     129                 : 
     130                 : ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
     131         8640643 : {
     132         8640643 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     133                 :                        GC_ZVAL_ADDRESS(zv) != NULL &&
     134                 :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     135                 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     136                 :                             GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
     137                 :                 /* The given zval is a garbage that is going to be deleted by
     138                 :                  * currently running GC */
     139           10026 :                 return;
     140                 :         }
     141                 : 
     142         8630617 :         if (zv->type == IS_OBJECT) {
     143         1239614 :                 GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
     144         1239614 :                 return;
     145                 :         }
     146                 : 
     147                 :         GC_BENCH_INC(zval_possible_root);
     148                 : 
     149         7391003 :         if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
     150         1886512 :                 GC_ZVAL_SET_PURPLE(zv);
     151                 : 
     152         1886512 :                 if (!GC_ZVAL_ADDRESS(zv)) {
     153         1886512 :                         gc_root_buffer *newRoot = GC_G(unused);
     154                 : 
     155         1886512 :                         if (newRoot) {
     156         1728459 :                                 GC_G(unused) = newRoot->prev;
     157          158053 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     158          158021 :                                 newRoot = GC_G(first_unused);
     159          158021 :                                 GC_G(first_unused)++;
     160                 :                         } else {
     161              32 :                                 if (!GC_G(gc_enabled)) {
     162              19 :                                         GC_ZVAL_SET_BLACK(zv);
     163              19 :                                         return;
     164                 :                                 }
     165              13 :                                 zv->refcount__gc++;
     166              13 :                                 gc_collect_cycles(TSRMLS_C);
     167              13 :                                 zv->refcount__gc--;
     168              13 :                                 newRoot = GC_G(unused);
     169              13 :                                 if (!newRoot) {
     170               0 :                                         return;
     171                 :                                 }
     172              13 :                                 GC_ZVAL_SET_PURPLE(zv);
     173              13 :                                 GC_G(unused) = newRoot->prev;
     174                 :                         }
     175                 : 
     176         1886493 :                         newRoot->next = GC_G(roots).next;
     177         1886493 :                         newRoot->prev = &GC_G(roots);
     178         1886493 :                         GC_G(roots).next->prev = newRoot;
     179         1886493 :                         GC_G(roots).next = newRoot;
     180                 : 
     181         1886493 :                         GC_ZVAL_SET_ADDRESS(zv, newRoot);
     182                 : 
     183         1886493 :                         newRoot->handle = 0;
     184         1886493 :                         newRoot->u.pz = zv;
     185                 : 
     186                 :                         GC_BENCH_INC(zval_buffered);
     187                 :                         GC_BENCH_INC(root_buf_length);
     188                 :                         GC_BENCH_PEAK(root_buf_peak, root_buf_length);
     189                 :                 }
     190                 :         }
     191                 : }
     192                 : 
     193                 : ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
     194         1448019 : {
     195                 :         struct _store_object *obj;
     196                 : 
     197         1448019 :         if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL ||
     198                 :             EG(objects_store).object_buckets == NULL)) {
     199            3945 :                 return;
     200                 :         }
     201                 : 
     202                 :         GC_BENCH_INC(zobj_possible_root);
     203                 : 
     204         1444074 :         obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     205         1444074 :         if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
     206          614687 :                 GC_SET_PURPLE(obj->buffered);
     207          614687 :                 if (!GC_ADDRESS(obj->buffered)) {
     208          614687 :                         gc_root_buffer *newRoot = GC_G(unused);
     209                 : 
     210          614687 :                         if (newRoot) {
     211          594783 :                                 GC_G(unused) = newRoot->prev;
     212           19904 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     213           19904 :                                 newRoot = GC_G(first_unused);
     214           19904 :                                 GC_G(first_unused)++;
     215                 :                         } else {
     216               0 :                                 if (!GC_G(gc_enabled)) {
     217               0 :                                         GC_ZVAL_SET_BLACK(zv);
     218               0 :                                         return;
     219                 :                                 }
     220               0 :                                 zv->refcount__gc++;
     221               0 :                                 gc_collect_cycles(TSRMLS_C);
     222               0 :                                 zv->refcount__gc--;
     223               0 :                                 newRoot = GC_G(unused);
     224               0 :                                 if (!newRoot) {
     225               0 :                                         return;
     226                 :                                 }
     227               0 :                                 obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     228               0 :                                 GC_SET_PURPLE(obj->buffered);
     229               0 :                                 GC_G(unused) = newRoot->prev;
     230                 :                         }
     231                 : 
     232          614687 :                         newRoot->next = GC_G(roots).next;
     233          614687 :                         newRoot->prev = &GC_G(roots);
     234          614687 :                         GC_G(roots).next->prev = newRoot;
     235          614687 :                         GC_G(roots).next = newRoot;
     236                 : 
     237          614687 :                         GC_SET_ADDRESS(obj->buffered, newRoot);
     238                 : 
     239          614687 :                         newRoot->handle = Z_OBJ_HANDLE_P(zv);
     240          614687 :                         newRoot->u.handlers = Z_OBJ_HT_P(zv);
     241                 : 
     242                 :                         GC_BENCH_INC(zobj_buffered);
     243                 :                         GC_BENCH_INC(root_buf_length);
     244                 :                         GC_BENCH_PEAK(root_buf_peak, root_buf_length);
     245                 :                 }
     246                 :         }
     247                 : }
     248                 : 
     249                 : ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC)
     250         1744399 : {
     251         1744399 :         gc_root_buffer* root_buffer = GC_ADDRESS(((zval_gc_info*)zv)->u.buffered);
     252                 : 
     253         1744399 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     254                 :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     255                 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     256                 :                             GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
     257                 :                 /* The given zval is a garbage that is going to be deleted by
     258                 :                  * currently running GC */
     259               0 :                 if (GC_G(next_to_free) == (zval_gc_info*)zv) {
     260               0 :                         GC_G(next_to_free) = ((zval_gc_info*)zv)->u.next;
     261                 :                 }
     262               0 :                 return;
     263                 :         }
     264                 :         GC_BENCH_INC(zval_remove_from_buffer);
     265         1744399 :         GC_REMOVE_FROM_BUFFER(root_buffer);
     266         1744399 :         ((zval_gc_info*)zv)->u.buffered = NULL;
     267                 : }
     268                 : 
     269                 : static void zval_scan_black(zval *pz TSRMLS_DC)
     270          252422 : {
     271                 :         Bucket *p;
     272                 : 
     273          252422 : tail_call:
     274          252422 :         p = NULL;
     275          252422 :         GC_ZVAL_SET_BLACK(pz);
     276                 : 
     277          266430 :         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     278           14008 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     279                 : 
     280           14008 :                 obj->refcount++;
     281           14008 :                 if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
     282           14006 :                         GC_SET_BLACK(obj->buffered);
     283           14006 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     284                 :                                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     285           14006 :                                 p = Z_OBJPROP_P(pz)->pListHead;
     286                 :                         }
     287                 :                 }
     288          238414 :         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     289          123063 :                 if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     290          123063 :                         p = Z_ARRVAL_P(pz)->pListHead;
     291                 :                 }
     292                 :         }
     293          539140 :         while (p != NULL) {
     294          150358 :                 pz = *(zval**)p->pData;
     295          150358 :                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     296          150358 :                         pz->refcount__gc++;
     297                 :                 }
     298          150358 :                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     299          129354 :                         if (p->pListNext == NULL) {
     300          116062 :                                 goto tail_call;
     301                 :                         } else {
     302           13292 :                                 zval_scan_black(pz TSRMLS_CC);
     303                 :                         }
     304                 :                 }
     305           34296 :                 p = p->pListNext;
     306                 :         }
     307          136360 : }
     308                 : 
     309                 : static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
     310            2004 : {
     311                 :         Bucket *p;
     312                 : 
     313            2004 :         GC_SET_BLACK(obj->buffered);
     314            2004 :         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     315                 :                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     316            2004 :                 p = Z_OBJPROP_P(pz)->pListHead;
     317            6018 :                 while (p != NULL) {
     318            2010 :                         pz = *(zval**)p->pData;
     319            2010 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     320            2010 :                                 pz->refcount__gc++;
     321                 :                         }
     322            2010 :                         if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     323            2010 :                                 zval_scan_black(pz TSRMLS_CC);
     324                 :                         }
     325            2010 :                         p = p->pListNext;
     326                 :                 }
     327                 :         }
     328            2004 : }
     329                 : 
     330                 : static void zval_mark_grey(zval *pz TSRMLS_DC)
     331          335591 : {
     332                 :         Bucket *p;
     333                 : 
     334          335591 : tail_call:
     335          335591 :         if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
     336          283544 :                 p = NULL;
     337                 :                 GC_BENCH_INC(zval_marked_grey);
     338          283544 :                 GC_ZVAL_SET_COLOR(pz, GC_GREY);
     339                 : 
     340          307573 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     341           24029 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     342                 : 
     343           24029 :                         obj->refcount--;
     344           24029 :                         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     345                 :                                 GC_BENCH_INC(zobj_marked_grey);
     346           14015 :                                 GC_SET_COLOR(obj->buffered, GC_GREY);
     347           14015 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     348                 :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     349           14015 :                                         p = Z_OBJPROP_P(pz)->pListHead;
     350                 :                                 }
     351                 :                         }
     352          259515 :                 } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     353          144112 :                         if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     354               2 :                                 GC_ZVAL_SET_BLACK(pz);
     355                 :                         } else {
     356          144110 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     357                 :                         }
     358                 :                 }
     359          590441 :                 while (p != NULL) {
     360          181471 :                         pz = *(zval**)p->pData;
     361          181471 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     362          181470 :                                 pz->refcount__gc--;
     363                 :                         }
     364          181471 :                         if (p->pListNext == NULL) {
     365          158118 :                                 goto tail_call;
     366                 :                         } else {
     367           23353 :                                 zval_mark_grey(pz TSRMLS_CC);
     368                 :                         }
     369           23353 :                         p = p->pListNext;
     370                 :                 }
     371                 :         }
     372          177473 : }
     373                 : 
     374                 : static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
     375            2016 : {
     376                 :         Bucket *p;
     377                 : 
     378            2016 :         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     379                 :                 GC_BENCH_INC(zobj_marked_grey);
     380            2016 :                 GC_SET_COLOR(obj->buffered, GC_GREY);
     381            2016 :                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     382                 :                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     383            2016 :                         p = Z_OBJPROP_P(pz)->pListHead;
     384           16058 :                         while (p != NULL) {
     385           12026 :                                 pz = *(zval**)p->pData;
     386           12026 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     387           12026 :                                         pz->refcount__gc--;
     388                 :                                 }
     389           12026 :                                 zval_mark_grey(pz TSRMLS_CC);
     390           12026 :                                 p = p->pListNext;
     391                 :                         }
     392                 :                 }
     393                 :         }
     394            2016 : }
     395                 : 
     396                 : static void gc_mark_roots(TSRMLS_D)
     397              67 : {
     398              67 :         gc_root_buffer *current = GC_G(roots).next;
     399                 : 
     400          144266 :         while (current != &GC_G(roots)) {
     401          146161 :                 if (current->handle && EG(objects_store).object_buckets) {
     402            2029 :                         struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     403                 : 
     404            2029 :                         if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
     405                 :                                 zval z;
     406                 : 
     407            2016 :                                 INIT_PZVAL(&z);
     408            2016 :                                 Z_OBJ_HANDLE(z) = current->handle;
     409            2016 :                                 Z_OBJ_HT(z) = current->u.handlers;
     410            2016 :                                 zobj_mark_grey(obj, &z TSRMLS_CC);
     411                 :                         } else {
     412              13 :                                 GC_SET_ADDRESS(obj->buffered, NULL);
     413              13 :                                 GC_REMOVE_FROM_BUFFER(current);
     414                 :                         }
     415                 :                 } else {
     416          142103 :                         if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
     417          142094 :                                 zval_mark_grey(current->u.pz TSRMLS_CC);
     418                 :                         } else {
     419               9 :                                 GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     420               9 :                                 GC_REMOVE_FROM_BUFFER(current);
     421                 :                         }
     422                 :                 }
     423          144132 :                 current = current->next;
     424                 :         }
     425              67 : }
     426                 : 
     427                 : static int zval_scan(zval *pz TSRMLS_DC)
     428          185228 : {
     429                 :         Bucket *p;
     430                 : 
     431          185228 : tail_call:      
     432          185228 :         if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
     433          154183 :                 p = NULL;
     434          154183 :                 if (pz->refcount__gc > 0) {
     435          121058 :                         zval_scan_black(pz TSRMLS_CC);
     436                 :                 } else {
     437           33125 :                         GC_ZVAL_SET_COLOR(pz, GC_WHITE);
     438           43149 :                         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     439           10024 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     440                 : 
     441           10024 :                                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     442              11 :                                         if (obj->refcount > 0) {
     443               1 :                                                 zobj_scan_black(obj, pz TSRMLS_CC);
     444                 :                                         } else {
     445              10 :                                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     446              10 :                                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     447                 :                                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     448              10 :                                                         p = Z_OBJPROP_P(pz)->pListHead;
     449                 :                                                 }
     450                 :                                         }
     451                 :                                 }
     452           23101 :                         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     453           21049 :                                 if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     454               0 :                                         GC_ZVAL_SET_BLACK(pz);
     455                 :                                 } else {
     456           21049 :                                         p = Z_ARRVAL_P(pz)->pListHead;
     457                 :                                 }
     458                 :                         }
     459                 :                 }
     460          318428 :                 while (p != NULL) {
     461           31117 :                         if (p->pListNext == NULL) {
     462           21055 :                                 pz = *(zval**)p->pData;
     463           21055 :                                 goto tail_call;
     464                 :                         } else {
     465           10062 :                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     466                 :                         }
     467           10062 :                         p = p->pListNext;
     468                 :                 }
     469                 :         }
     470          164173 :         return 0;
     471                 : }
     472                 : 
     473                 : static void zobj_scan(zval *pz TSRMLS_DC)
     474            4016 : {
     475                 :         Bucket *p;
     476                 : 
     477            4016 :         if (EG(objects_store).object_buckets) {
     478            4016 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     479                 : 
     480            4016 :                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     481            4016 :                         if (obj->refcount > 0) {
     482            2003 :                                 zobj_scan_black(obj, pz TSRMLS_CC);
     483                 :                         } else {
     484            2013 :                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     485            2013 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     486                 :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     487            2013 :                                         p = Z_OBJPROP_P(pz)->pListHead;
     488           16043 :                                         while (p != NULL) {
     489           12017 :                                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     490           12017 :                                                 p = p->pListNext;
     491                 :                                         }
     492                 :                                 }
     493                 :                         }
     494                 :                 }
     495                 :         }
     496            4016 : }
     497                 : 
     498                 : static void gc_scan_roots(TSRMLS_D)
     499              67 : {
     500              67 :         gc_root_buffer *current = GC_G(roots).next;
     501                 : 
     502          146244 :         while (current != &GC_G(roots)) {
     503          146110 :                 if (current->handle) {
     504                 :                         zval z;
     505                 : 
     506            4016 :                         INIT_PZVAL(&z);
     507            4016 :                         Z_OBJ_HANDLE(z) = current->handle;
     508            4016 :                         Z_OBJ_HT(z) = current->u.handlers;
     509            4016 :                         zobj_scan(&z TSRMLS_CC);
     510                 :                 } else {
     511          142094 :                         zval_scan(current->u.pz TSRMLS_CC);
     512                 :                 }
     513          146110 :                 current = current->next;
     514                 :         }
     515              67 : }
     516                 : 
     517                 : static void zval_collect_white(zval *pz TSRMLS_DC)
     518          183223 : {
     519                 :         Bucket *p;
     520                 : 
     521          183223 : tail_call:
     522          183223 :         if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
     523           31120 :                 p = NULL;
     524           31120 :                 GC_ZVAL_SET_BLACK(pz);
     525                 : 
     526           41141 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     527           10021 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     528                 : 
     529           10021 :                         if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     530               9 :                                 GC_SET_BLACK(obj->buffered);
     531                 : 
     532               9 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     533                 :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     534               9 :                                         p = Z_OBJPROP_P(pz)->pListHead;
     535                 :                                 }
     536                 :                         }
     537                 :                 } else {
     538           21099 :                         if (Z_TYPE_P(pz) == IS_ARRAY) {
     539           21047 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     540                 :                         }
     541                 :                 }
     542                 : 
     543                 :                 /* restore refcount and put into list to free */
     544           31120 :                 pz->refcount__gc++;
     545           31120 :                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     546           31120 :                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     547                 : 
     548           72301 :                 while (p != NULL) {
     549           31113 :                         pz = *(zval**)p->pData;
     550           31113 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     551           31112 :                                 pz->refcount__gc++;
     552                 :                         }
     553           31113 :                         if (p->pListNext == NULL) {
     554           21052 :                                 goto tail_call;
     555                 :                         } else {
     556           10061 :                                 zval_collect_white(pz TSRMLS_CC);
     557                 :                         }
     558           10061 :                         p = p->pListNext;
     559                 :                 }
     560                 :         }
     561          162171 : }
     562                 : 
     563                 : static void zobj_collect_white(zval *pz TSRMLS_DC)
     564            4016 : {
     565                 :         Bucket *p;
     566                 : 
     567            4016 :         if (EG(objects_store).object_buckets) {
     568            4016 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     569                 : 
     570            4016 :                 if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     571              12 :                         GC_SET_BLACK(obj->buffered);
     572                 : 
     573              12 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     574                 :                                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     575              12 :                                 p = Z_OBJPROP_P(pz)->pListHead;
     576           10040 :                                 while (p != NULL) {
     577           10016 :                                         pz = *(zval**)p->pData;
     578           10016 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     579           10016 :                                                 pz->refcount__gc++;
     580                 :                                         }
     581           10016 :                                         zval_collect_white(pz TSRMLS_CC);
     582           10016 :                                         p = p->pListNext;
     583                 :                                 }
     584                 :                         }
     585                 :                 }
     586                 :         }
     587            4016 : }
     588                 : 
     589                 : static void gc_collect_roots(TSRMLS_D)
     590              67 : {
     591              67 :         gc_root_buffer *current = GC_G(roots).next;
     592                 : 
     593          146244 :         while (current != &GC_G(roots)) {
     594          150126 :                 if (current->handle && EG(objects_store).object_buckets) {
     595            4016 :                         struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     596                 :                         zval z;
     597                 : 
     598            4016 :                         GC_SET_ADDRESS(obj->buffered, NULL);
     599            4016 :                         INIT_PZVAL(&z);
     600            4016 :                         Z_OBJ_HANDLE(z) = current->handle;
     601            4016 :                         Z_OBJ_HT(z) = current->u.handlers;
     602            4016 :                         zobj_collect_white(&z TSRMLS_CC);
     603                 :                 } else {
     604          142094 :                         GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     605          142094 :                         zval_collect_white(current->u.pz TSRMLS_CC);
     606                 :                 }
     607                 : 
     608          146110 :                 GC_REMOVE_FROM_BUFFER(current);
     609          146110 :                 current = current->next;
     610                 :         }
     611              67 : }
     612                 : 
     613                 : #define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
     614                 : 
     615                 : ZEND_API int gc_collect_cycles(TSRMLS_D)
     616           16347 : {
     617           16347 :         int count = 0;
     618                 : 
     619           16347 :         if (GC_G(roots).next != &GC_G(roots)) {
     620                 :                 zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
     621                 : 
     622              67 :                 if (GC_G(gc_active)) {
     623               0 :                         return 0;
     624                 :                 }
     625              67 :                 GC_G(gc_runs)++;
     626              67 :                 GC_G(zval_to_free) = FREE_LIST_END;
     627              67 :                 GC_G(gc_active) = 1;
     628              67 :                 gc_mark_roots(TSRMLS_C);
     629              67 :                 gc_scan_roots(TSRMLS_C);
     630              67 :                 gc_collect_roots(TSRMLS_C);
     631                 : 
     632              67 :                 orig_free_list = GC_G(free_list);
     633              67 :                 orig_next_to_free = GC_G(next_to_free);
     634              67 :                 p = GC_G(free_list) = GC_G(zval_to_free);
     635              67 :                 GC_G(zval_to_free) = NULL;
     636              67 :                 GC_G(gc_active) = 0;
     637                 : 
     638                 :                 /* First call destructors */
     639           31254 :                 while (p != FREE_LIST_END) {
     640           31120 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     641           10021 :                                 if (EG(objects_store).object_buckets &&
     642                 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     643                 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
     644                 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
     645                 :                                         !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
     646                 : 
     647              21 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
     648              21 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
     649              21 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
     650              21 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
     651                 :                                 }
     652                 :                         }
     653           31120 :                         count++;
     654           31120 :                         p = p->u.next;
     655                 :                 }
     656                 : 
     657                 :                 /* Destroy zvals */
     658              67 :                 p = GC_G(free_list);
     659           31254 :                 while (p != FREE_LIST_END) {
     660           31120 :                         GC_G(next_to_free) = p->u.next;
     661           31120 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     662           10021 :                                 if (EG(objects_store).object_buckets &&
     663                 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     664                 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
     665              21 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
     666              21 :                                         Z_TYPE(p->z) = IS_NULL;
     667              21 :                                         zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
     668                 :                                 }
     669           21099 :                         } else if (Z_TYPE(p->z) == IS_ARRAY) {
     670           21047 :                                 Z_TYPE(p->z) = IS_NULL;
     671           21047 :                                 zend_hash_destroy(Z_ARRVAL(p->z));
     672           21047 :                                 FREE_HASHTABLE(Z_ARRVAL(p->z));
     673                 :                         } else {
     674              52 :                                 zval_dtor(&p->z);
     675              52 :                                 Z_TYPE(p->z) = IS_NULL;
     676                 :                         }
     677           31120 :                         p = GC_G(next_to_free);
     678                 :                 }
     679                 : 
     680                 :                 /* Free zvals */
     681              67 :                 p = GC_G(free_list);
     682           31254 :                 while (p != FREE_LIST_END) {
     683           31120 :                         q = p->u.next;
     684           31120 :                         FREE_ZVAL_EX(&p->z);
     685           31120 :                         p = q;
     686                 :                 }
     687              67 :                 GC_G(collected) += count;
     688              67 :                 GC_G(free_list) = orig_free_list;
     689              67 :                 GC_G(next_to_free) = orig_next_to_free;
     690                 :         }
     691                 : 
     692           16347 :         return count;
     693                 : }
     694                 : 
     695                 : /*
     696                 :  * Local variables:
     697                 :  * tab-width: 4
     698                 :  * c-basic-offset: 4
     699                 :  * indent-tabs-mode: t
     700                 :  * End:
     701                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:26:54 +0000 (3 days ago)

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