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

LCOV - code coverage report
Current view: top level - Zend - zend_gc.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 363 381 95.3 %
Date: 2014-04-18 Functions: 21 21 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2013 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$ */
      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       19376 : static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
      34             : {
      35       19376 :         if (gc_globals->buf) {
      36       19375 :                 free(gc_globals->buf);
      37       19375 :                 gc_globals->buf = NULL;
      38             :         }       
      39       19376 : }
      40             : 
      41       19341 : static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
      42             : {
      43       19341 :         gc_globals->gc_enabled = 0;
      44       19341 :         gc_globals->gc_active = 0;
      45             : 
      46       19341 :         gc_globals->buf = NULL;
      47             : 
      48       19341 :         gc_globals->roots.next = &gc_globals->roots;
      49       19341 :         gc_globals->roots.prev = &gc_globals->roots;
      50       19341 :         gc_globals->unused = NULL;
      51       19341 :         gc_globals->zval_to_free = NULL;
      52       19341 :         gc_globals->free_list = NULL;
      53       19341 :         gc_globals->next_to_free = NULL;
      54             : 
      55       19341 :         gc_globals->gc_runs = 0;
      56       19341 :         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       19341 : }
      71             : 
      72       19341 : ZEND_API void gc_globals_ctor(TSRMLS_D)
      73             : {
      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       19341 :         gc_globals_ctor_ex(&gc_globals);
      78             : #endif
      79       19341 : }
      80             : 
      81       19376 : ZEND_API void gc_globals_dtor(TSRMLS_D)
      82             : {
      83             : #ifndef ZTS
      84       19376 :         root_buffer_dtor(&gc_globals TSRMLS_DC);
      85             : #endif
      86       19376 : }
      87             : 
      88       38667 : ZEND_API void gc_reset(TSRMLS_D)
      89             : {
      90       38667 :         GC_G(gc_runs) = 0;
      91       38667 :         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       38667 :         GC_G(roots).next = &GC_G(roots);
     107       38667 :         GC_G(roots).prev = &GC_G(roots);
     108             : 
     109       38667 :         if (GC_G(buf)) {
     110       38665 :                 GC_G(unused) = NULL;
     111       38665 :                 GC_G(first_unused) = GC_G(buf);
     112             : 
     113       38665 :                 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       38667 : }
     120             : 
     121       19350 : ZEND_API void gc_init(TSRMLS_D)
     122             : {
     123       19350 :         if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
     124       19340 :                 GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
     125       19340 :                 GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
     126       19340 :                 gc_reset(TSRMLS_C);
     127             :         }
     128       19350 : }
     129             : 
     130    12332609 : ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
     131             : {
     132    12684087 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     133             :                        GC_ZVAL_ADDRESS(zv) != NULL &&
     134             :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     135      176032 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     136      175446 :                             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      176032 :                 return;
     140             :         }
     141             : 
     142    12156577 :         if (zv->type == IS_OBJECT) {
     143     4948239 :                 GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
     144     4948239 :                 return;
     145             :         }
     146             : 
     147             :         GC_BENCH_INC(zval_possible_root);
     148             : 
     149     7208338 :         if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
     150     2083446 :                 GC_ZVAL_SET_PURPLE(zv);
     151             : 
     152     2083446 :                 if (!GC_ZVAL_ADDRESS(zv)) {
     153     2083446 :                         gc_root_buffer *newRoot = GC_G(unused);
     154             : 
     155     2083446 :                         if (newRoot) {
     156     1890518 :                                 GC_G(unused) = newRoot->prev;
     157      192928 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     158      192894 :                                 newRoot = GC_G(first_unused);
     159      192894 :                                 GC_G(first_unused)++;
     160             :                         } else {
     161          34 :                                 if (!GC_G(gc_enabled)) {
     162          19 :                                         GC_ZVAL_SET_BLACK(zv);
     163          19 :                                         return;
     164             :                                 }
     165          15 :                                 zv->refcount__gc++;
     166          15 :                                 gc_collect_cycles(TSRMLS_C);
     167          15 :                                 zv->refcount__gc--;
     168          15 :                                 newRoot = GC_G(unused);
     169          15 :                                 if (!newRoot) {
     170           0 :                                         return;
     171             :                                 }
     172          15 :                                 GC_ZVAL_SET_PURPLE(zv);
     173          15 :                                 GC_G(unused) = newRoot->prev;
     174             :                         }
     175             : 
     176     2083427 :                         newRoot->next = GC_G(roots).next;
     177     2083427 :                         newRoot->prev = &GC_G(roots);
     178     2083427 :                         GC_G(roots).next->prev = newRoot;
     179     2083427 :                         GC_G(roots).next = newRoot;
     180             : 
     181     2083427 :                         GC_ZVAL_SET_ADDRESS(zv, newRoot);
     182             : 
     183     2083427 :                         newRoot->handle = 0;
     184     2083427 :                         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     5311083 : ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
     194             : {
     195             :         struct _store_object *obj;
     196             : 
     197     5311083 :         if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL ||
     198             :             EG(objects_store).object_buckets == NULL)) {
     199           0 :                 return;
     200             :         }
     201             : 
     202             :         GC_BENCH_INC(zobj_possible_root);
     203             : 
     204     5311083 :         obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     205     5311083 :         if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
     206     1478550 :                 GC_SET_PURPLE(obj->buffered);
     207     1478550 :                 if (!GC_ADDRESS(obj->buffered)) {
     208     1478550 :                         gc_root_buffer *newRoot = GC_G(unused);
     209             : 
     210     1478550 :                         if (newRoot) {
     211     1428627 :                                 GC_G(unused) = newRoot->prev;
     212       49923 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     213       49903 :                                 newRoot = GC_G(first_unused);
     214       49903 :                                 GC_G(first_unused)++;
     215             :                         } else {
     216          20 :                                 if (!GC_G(gc_enabled)) {
     217           0 :                                         GC_ZVAL_SET_BLACK(zv);
     218           0 :                                         return;
     219             :                                 }
     220          20 :                                 zv->refcount__gc++;
     221          20 :                                 gc_collect_cycles(TSRMLS_C);
     222          20 :                                 zv->refcount__gc--;
     223          20 :                                 newRoot = GC_G(unused);
     224          20 :                                 if (!newRoot) {
     225           0 :                                         return;
     226             :                                 }
     227          20 :                                 obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     228          20 :                                 GC_SET_PURPLE(obj->buffered);
     229          20 :                                 GC_G(unused) = newRoot->prev;
     230             :                         }
     231             : 
     232     1478550 :                         newRoot->next = GC_G(roots).next;
     233     1478550 :                         newRoot->prev = &GC_G(roots);
     234     1478550 :                         GC_G(roots).next->prev = newRoot;
     235     1478550 :                         GC_G(roots).next = newRoot;
     236             : 
     237     1478550 :                         GC_SET_ADDRESS(obj->buffered, newRoot);
     238             : 
     239     1478550 :                         newRoot->handle = Z_OBJ_HANDLE_P(zv);
     240     1478550 :                         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     1915995 : ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC)
     250             : {
     251     1915995 :         gc_root_buffer* root_buffer = GC_ADDRESS(((zval_gc_info*)zv)->u.buffered);
     252             : 
     253     1915995 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     254             :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     255           0 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     256           0 :                             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             :         GC_REMOVE_FROM_BUFFER(root_buffer);
     266     1915995 :         ((zval_gc_info*)zv)->u.buffered = NULL;
     267             : }
     268             : 
     269      356740 : static void zval_scan_black(zval *pz TSRMLS_DC)
     270             : {
     271             :         Bucket *p;
     272             : 
     273             : tail_call:
     274      356740 :         p = NULL;
     275      356740 :         GC_ZVAL_SET_BLACK(pz);
     276             : 
     277      373679 :         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     278       16939 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     279             : 
     280       16939 :                 obj->refcount++;
     281       16939 :                 if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
     282       16938 :                         GC_SET_BLACK(obj->buffered);
     283       16938 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     284             :                                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     285       16938 :                                 HashTable *props = Z_OBJPROP_P(pz);
     286       16938 :                                 if(!props) {
     287           0 :                                         return;
     288             :                                 }
     289       16938 :                                 p = props->pListHead;
     290             :                         }
     291             :                 }
     292      339801 :         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     293      138017 :                 if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     294      138017 :                         p = Z_ARRVAL_P(pz)->pListHead;
     295             :                 }
     296             :         }
     297      835879 :         while (p != NULL) {
     298      240463 :                 pz = *(zval**)p->pData;
     299      240463 :                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     300      240463 :                         pz->refcount__gc++;
     301             :                 }
     302      240463 :                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     303      185599 :                         if (p->pListNext == NULL) {
     304      118064 :                                 goto tail_call;
     305             :                         } else {
     306       67535 :                                 zval_scan_black(pz TSRMLS_CC);
     307             :                         }
     308             :                 }
     309      122399 :                 p = p->pListNext;
     310             :         }
     311             : }
     312             : 
     313      111975 : static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
     314             : {
     315             :         Bucket *p;
     316             : 
     317      111975 :         GC_SET_BLACK(obj->buffered);
     318      111975 :         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     319             :                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     320      111975 :                 HashTable *props = Z_OBJPROP_P(pz);
     321      111975 :                 if(!props) {
     322        2000 :                         return;
     323             :                 }
     324      109975 :                 p = props->pListHead;
     325      269950 :                 while (p != NULL) {
     326       50000 :                         pz = *(zval**)p->pData;
     327       50000 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     328       50000 :                                 pz->refcount__gc++;
     329             :                         }
     330       50000 :                         if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     331       50000 :                                 zval_scan_black(pz TSRMLS_CC);
     332             :                         }
     333       50000 :                         p = p->pListNext;
     334             :                 }
     335             :         }
     336             : }
     337             : 
     338      850989 : static void zval_mark_grey(zval *pz TSRMLS_DC)
     339             : {
     340             :         Bucket *p;
     341             : 
     342             : tail_call:
     343      850989 :         if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
     344      573894 :                 p = NULL;
     345             :                 GC_BENCH_INC(zval_marked_grey);
     346      573894 :                 GC_ZVAL_SET_COLOR(pz, GC_GREY);
     347             : 
     348      683870 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     349      109976 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     350             : 
     351      109976 :                         obj->refcount--;
     352      109976 :                         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     353             :                                 GC_BENCH_INC(zobj_marked_grey);
     354       21640 :                                 GC_SET_COLOR(obj->buffered, GC_GREY);
     355       21640 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     356             :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     357       21640 :                                         HashTable *props = Z_OBJPROP_P(pz);
     358       21640 :                                         if(!props) {
     359           0 :                                                 return;
     360             :                                         }
     361       21640 :                                         p = props->pListHead;
     362             :                                 }
     363             :                         }
     364      463918 :                 } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     365      262079 :                         if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     366           2 :                                 GC_ZVAL_SET_BLACK(pz);
     367             :                         } else {
     368      262077 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     369             :                         }
     370             :                 }
     371     1331078 :                 while (p != NULL) {
     372      466991 :                         pz = *(zval**)p->pData;
     373      466991 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     374      466990 :                                 pz->refcount__gc--;
     375             :                         }
     376      466991 :                         if (p->pListNext == NULL) {
     377      283701 :                                 goto tail_call;
     378             :                         } else {
     379      183290 :                                 zval_mark_grey(pz TSRMLS_CC);
     380             :                         }
     381      183290 :                         p = p->pListNext;
     382             :                 }
     383             :         }
     384             : }
     385             : 
     386      190310 : static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
     387             : {
     388             :         Bucket *p;
     389             : 
     390      190310 :         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     391             :                 GC_BENCH_INC(zobj_marked_grey);
     392      190310 :                 GC_SET_COLOR(obj->buffered, GC_GREY);
     393      190310 :                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     394             :                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     395      190310 :                         HashTable *props = Z_OBJPROP_P(pz);
     396      190310 :                         if(!props) {
     397        2000 :                                 return;
     398             :                         }
     399      188310 :                         p = props->pListHead;
     400      593256 :                         while (p != NULL) {
     401      216636 :                                 pz = *(zval**)p->pData;
     402      216636 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     403      216636 :                                         pz->refcount__gc--;
     404             :                                 }
     405      216636 :                                 zval_mark_grey(pz TSRMLS_CC);
     406      216636 :                                 p = p->pListNext;
     407             :                         }
     408             :                 }
     409             :         }
     410             : }
     411             : 
     412          95 : static void gc_mark_roots(TSRMLS_D)
     413             : {
     414          95 :         gc_root_buffer *current = GC_G(roots).next;
     415             : 
     416      364337 :         while (current != &GC_G(roots)) {
     417      364147 :                 if (current->handle) {
     418      196692 :                         if (EG(objects_store).object_buckets) {
     419      196692 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     420             : 
     421      196692 :                                 if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
     422             :                                         zval z;
     423             : 
     424      190310 :                                         INIT_PZVAL(&z);
     425      190310 :                                         Z_OBJ_HANDLE(z) = current->handle;
     426      190310 :                                         Z_OBJ_HT(z) = current->u.handlers;
     427      190310 :                                         zobj_mark_grey(obj, &z TSRMLS_CC);
     428             :                                 } else {
     429        6382 :                                         GC_SET_ADDRESS(obj->buffered, NULL);
     430             :                                         GC_REMOVE_FROM_BUFFER(current);
     431             :                                 }
     432             :                         }
     433             :                 } else {
     434      167455 :                         if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
     435      167362 :                                 zval_mark_grey(current->u.pz TSRMLS_CC);
     436             :                         } else {
     437          93 :                                 GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     438             :                                 GC_REMOVE_FROM_BUFFER(current);
     439             :                         }
     440             :                 }
     441      364147 :                 current = current->next;
     442             :         }
     443          95 : }
     444             : 
     445      628109 : static int zval_scan(zval *pz TSRMLS_DC)
     446             : {
     447             :         Bucket *p;
     448             : 
     449             : tail_call:      
     450      628109 :         if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
     451      372078 :                 p = NULL;
     452      372078 :                 if (pz->refcount__gc > 0) {
     453      121141 :                         zval_scan_black(pz TSRMLS_CC);
     454             :                 } else {
     455      250937 :                         GC_ZVAL_SET_COLOR(pz, GC_WHITE);
     456      360849 :                         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     457      109912 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     458             : 
     459      109912 :                                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     460       21597 :                                         if (obj->refcount > 0) {
     461           1 :                                                 zobj_scan_black(obj, pz TSRMLS_CC);
     462             :                                         } else {
     463       21596 :                                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     464       21596 :                                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     465             :                                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     466       21596 :                                                         HashTable *props = Z_OBJPROP_P(pz);
     467       21596 :                                                         if(!props) {
     468           0 :                                                                 return 0;
     469             :                                                         }
     470       21596 :                                                         p = props->pListHead;
     471             :                                                 }
     472             :                                         }
     473             :                                 }
     474      141025 :                         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     475      140970 :                                 if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     476           0 :                                         GC_ZVAL_SET_BLACK(pz);
     477             :                                 } else {
     478      140970 :                                         p = Z_ARRVAL_P(pz)->pListHead;
     479             :                                 }
     480             :                         }
     481             :                 }
     482      875704 :                 while (p != NULL) {
     483      294110 :                         if (p->pListNext == NULL) {
     484      162562 :                                 pz = *(zval**)p->pData;
     485      162562 :                                 goto tail_call;
     486             :                         } else {
     487      131548 :                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     488             :                         }
     489      131548 :                         p = p->pListNext;
     490             :                 }
     491             :         }
     492      465547 :         return 0;
     493             : }
     494             : 
     495      190310 : static void zobj_scan(zval *pz TSRMLS_DC)
     496             : {
     497             :         Bucket *p;
     498             : 
     499      190310 :         if (EG(objects_store).object_buckets) {
     500      190310 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     501             : 
     502      190310 :                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     503      190310 :                         if (obj->refcount > 0) {
     504      111974 :                                 zobj_scan_black(obj, pz TSRMLS_CC);
     505             :                         } else {
     506       78336 :                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     507       78336 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     508             :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     509       78336 :                                         HashTable *props = Z_OBJPROP_P(pz);
     510       78336 :                                         if(!props) {
     511           0 :                                                 return;
     512             :                                         }
     513       78336 :                                         p = props->pListHead;
     514      323309 :                                         while (p != NULL) {
     515      166637 :                                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     516      166637 :                                                 p = p->pListNext;
     517             :                                         }
     518             :                                 }
     519             :                         }
     520             :                 }
     521             :         }
     522             : }
     523             : 
     524          95 : static void gc_scan_roots(TSRMLS_D)
     525             : {
     526          95 :         gc_root_buffer *current = GC_G(roots).next;
     527             : 
     528      357862 :         while (current != &GC_G(roots)) {
     529      357672 :                 if (current->handle) {
     530             :                         zval z;
     531             : 
     532      190310 :                         INIT_PZVAL(&z);
     533      190310 :                         Z_OBJ_HANDLE(z) = current->handle;
     534      190310 :                         Z_OBJ_HT(z) = current->u.handlers;
     535      190310 :                         zobj_scan(&z TSRMLS_CC);
     536             :                 } else {
     537      167362 :                         zval_scan(current->u.pz TSRMLS_CC);
     538             :                 }
     539      357672 :                 current = current->next;
     540             :         }
     541          95 : }
     542             : 
     543      560526 : static void zval_collect_white(zval *pz TSRMLS_DC)
     544             : {
     545             :         Bucket *p;
     546             : 
     547             : tail_call:
     548      560526 :         if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
     549      217152 :                 p = NULL;
     550      217152 :                 GC_ZVAL_SET_BLACK(pz);
     551             : 
     552      310189 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     553       93037 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     554             : 
     555       93037 :                         if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     556             :                                 /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     557       20551 :                                 GC_SET_PURPLE(obj->buffered);
     558             : 
     559       20551 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     560             :                                              Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     561       20551 :                                         HashTable *props = Z_OBJPROP_P(pz);
     562       20551 :                                         if(!props) {
     563           0 :                                                 return;
     564             :                                         }
     565       20551 :                                         p = props->pListHead;
     566             :                                 }
     567             :                         }
     568             :                 } else {
     569      124115 :                         if (Z_TYPE_P(pz) == IS_ARRAY) {
     570      124060 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     571             :                         }
     572             :                 }
     573             : 
     574             :                 /* restore refcount and put into list to free */
     575      217152 :                 pz->refcount__gc++;
     576      217152 :                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     577      217152 :                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     578             : 
     579      547899 :                 while (p != NULL) {
     580      258202 :                         pz = *(zval**)p->pData;
     581      258202 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     582      258201 :                                 pz->refcount__gc++;
     583             :                         }
     584      258202 :                         if (p->pListNext == NULL) {
     585      144607 :                                 goto tail_call;
     586             :                         } else {
     587      113595 :                                 zval_collect_white(pz TSRMLS_CC);
     588             :                         }
     589      113595 :                         p = p->pListNext;
     590             :                 }
     591             :         }
     592             : }
     593             : 
     594      190310 : static void zobj_collect_white(zval *pz TSRMLS_DC)
     595             : {
     596             :         Bucket *p;
     597             : 
     598      190310 :         if (EG(objects_store).object_buckets) {
     599      190310 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     600             : 
     601      190310 :                 if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     602             :                         /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     603       62486 :                         GC_SET_PURPLE(obj->buffered);
     604             : 
     605       62486 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     606             :                                      Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
     607       62486 :                                 HashTable *props = Z_OBJPROP_P(pz);
     608       62486 :                                 if(!props) {
     609           0 :                                         return;
     610             :                                 }
     611       62486 :                                 p = props->pListHead;
     612      259934 :                                 while (p != NULL) {
     613      134962 :                                         pz = *(zval**)p->pData;
     614      134962 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     615      134962 :                                                 pz->refcount__gc++;
     616             :                                         }
     617      134962 :                                         zval_collect_white(pz TSRMLS_CC);
     618      134962 :                                         p = p->pListNext;
     619             :                                 }
     620             :                         }
     621             :                 }
     622             :         }
     623             : }
     624             : 
     625          95 : static void gc_collect_roots(TSRMLS_D)
     626             : {
     627          95 :         gc_root_buffer *current = GC_G(roots).next;
     628             : 
     629      357862 :         while (current != &GC_G(roots)) {
     630      357672 :                 if (current->handle) {
     631      190310 :                         if (EG(objects_store).object_buckets) {
     632      190310 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     633             :                                 zval z;
     634             : 
     635      190310 :                                 GC_SET_ADDRESS(obj->buffered, NULL);
     636      190310 :                                 INIT_PZVAL(&z);
     637      190310 :                                 Z_OBJ_HANDLE(z) = current->handle;
     638      190310 :                                 Z_OBJ_HT(z) = current->u.handlers;
     639      190310 :                                 zobj_collect_white(&z TSRMLS_CC);
     640             :                         }
     641             :                 } else {
     642      167362 :                         GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     643      167362 :                         zval_collect_white(current->u.pz TSRMLS_CC);
     644             :                 }
     645             : 
     646             :                 GC_REMOVE_FROM_BUFFER(current);
     647      357672 :                 current = current->next;
     648             :         }
     649          95 : }
     650             : 
     651             : #define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
     652             : 
     653       17929 : ZEND_API int gc_collect_cycles(TSRMLS_D)
     654             : {
     655       17929 :         int count = 0;
     656             : 
     657       17929 :         if (GC_G(roots).next != &GC_G(roots)) {
     658             :                 zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
     659             : 
     660          95 :                 if (GC_G(gc_active)) {
     661           0 :                         return 0;
     662             :                 }
     663          95 :                 GC_G(gc_runs)++;
     664          95 :                 GC_G(zval_to_free) = FREE_LIST_END;
     665          95 :                 GC_G(gc_active) = 1;
     666          95 :                 gc_mark_roots(TSRMLS_C);
     667          95 :                 gc_scan_roots(TSRMLS_C);
     668          95 :                 gc_collect_roots(TSRMLS_C);
     669             : 
     670          95 :                 orig_free_list = GC_G(free_list);
     671          95 :                 orig_next_to_free = GC_G(next_to_free);
     672          95 :                 p = GC_G(free_list) = GC_G(zval_to_free);
     673          95 :                 GC_G(zval_to_free) = NULL;
     674          95 :                 GC_G(gc_active) = 0;
     675             : 
     676             :                 /* First call destructors */
     677      217342 :                 while (p != FREE_LIST_END) {
     678      217152 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     679      465185 :                                 if (EG(objects_store).object_buckets &&
     680       93037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     681       93037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
     682       93037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
     683       93037 :                                         !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
     684             : 
     685       83037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
     686       83037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
     687       83037 :                                         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);
     688       83037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
     689             :                                 }
     690             :                         }
     691      217152 :                         count++;
     692      217152 :                         p = p->u.next;
     693             :                 }
     694             : 
     695             :                 /* Destroy zvals */
     696          95 :                 p = GC_G(free_list);
     697      217342 :                 while (p != FREE_LIST_END) {
     698      217152 :                         GC_G(next_to_free) = p->u.next;
     699      217152 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     700      269111 :                                 if (EG(objects_store).object_buckets &&
     701       93037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     702       83037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
     703       83037 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
     704       83037 :                                         Z_TYPE(p->z) = IS_NULL;
     705       83037 :                                         zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
     706             :                                 }
     707      124115 :                         } else if (Z_TYPE(p->z) == IS_ARRAY) {
     708      124060 :                                 Z_TYPE(p->z) = IS_NULL;
     709      124060 :                                 zend_hash_destroy(Z_ARRVAL(p->z));
     710      124060 :                                 FREE_HASHTABLE(Z_ARRVAL(p->z));
     711             :                         } else {
     712          55 :                                 zval_dtor(&p->z);
     713          55 :                                 Z_TYPE(p->z) = IS_NULL;
     714             :                         }
     715      217152 :                         p = GC_G(next_to_free);
     716             :                 }
     717             : 
     718             :                 /* Free zvals */
     719          95 :                 p = GC_G(free_list);
     720      217342 :                 while (p != FREE_LIST_END) {
     721      217152 :                         q = p->u.next;
     722      217152 :                         FREE_ZVAL_EX(&p->z);
     723      217152 :                         p = q;
     724             :                 }
     725          95 :                 GC_G(collected) += count;
     726          95 :                 GC_G(free_list) = orig_free_list;
     727          95 :                 GC_G(next_to_free) = orig_next_to_free;
     728             :         }
     729             : 
     730       17929 :         return count;
     731             : }
     732             : 
     733             : /*
     734             :  * Local variables:
     735             :  * tab-width: 4
     736             :  * c-basic-offset: 4
     737             :  * indent-tabs-mode: t
     738             :  * End:
     739             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:22 +0000 (5 days ago)

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