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: 0 440 0.0 %
Date: 2014-04-16 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2014 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           0 : static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
      34             : {
      35           0 :         if (gc_globals->buf) {
      36           0 :                 free(gc_globals->buf);
      37           0 :                 gc_globals->buf = NULL;
      38             :         }       
      39           0 : }
      40             : 
      41           0 : static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
      42             : {
      43           0 :         gc_globals->gc_enabled = 0;
      44           0 :         gc_globals->gc_active = 0;
      45             : 
      46           0 :         gc_globals->buf = NULL;
      47             : 
      48           0 :         gc_globals->roots.next = &gc_globals->roots;
      49           0 :         gc_globals->roots.prev = &gc_globals->roots;
      50           0 :         gc_globals->unused = NULL;
      51           0 :         gc_globals->zval_to_free = NULL;
      52           0 :         gc_globals->free_list = NULL;
      53           0 :         gc_globals->next_to_free = NULL;
      54             : 
      55           0 :         gc_globals->gc_runs = 0;
      56           0 :         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           0 : }
      71             : 
      72           0 : 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           0 :         gc_globals_ctor_ex(&gc_globals);
      78             : #endif
      79           0 : }
      80             : 
      81           0 : ZEND_API void gc_globals_dtor(TSRMLS_D)
      82             : {
      83             : #ifndef ZTS
      84           0 :         root_buffer_dtor(&gc_globals TSRMLS_DC);
      85             : #endif
      86           0 : }
      87             : 
      88           0 : ZEND_API void gc_reset(TSRMLS_D)
      89             : {
      90           0 :         GC_G(gc_runs) = 0;
      91           0 :         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           0 :         GC_G(roots).next = &GC_G(roots);
     107           0 :         GC_G(roots).prev = &GC_G(roots);
     108             : 
     109           0 :         if (GC_G(buf)) {
     110           0 :                 GC_G(unused) = NULL;
     111           0 :                 GC_G(first_unused) = GC_G(buf);
     112             : 
     113           0 :                 GC_G(zval_to_free) = NULL;
     114             :         } else {
     115           0 :                 GC_G(unused) = NULL;
     116           0 :                 GC_G(first_unused) = NULL;
     117           0 :                 GC_G(last_unused) = NULL;
     118             :         }
     119           0 : }
     120             : 
     121           0 : ZEND_API void gc_init(TSRMLS_D)
     122             : {
     123           0 :         if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
     124           0 :                 GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
     125           0 :                 GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
     126           0 :                 gc_reset(TSRMLS_C);
     127             :         }
     128           0 : }
     129             : 
     130           0 : ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
     131             : {
     132           0 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     133             :                        GC_ZVAL_ADDRESS(zv) != NULL &&
     134             :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     135           0 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     136           0 :                             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           0 :                 return;
     140             :         }
     141             : 
     142           0 :         if (zv->type == IS_OBJECT) {
     143           0 :                 GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
     144           0 :                 return;
     145             :         }
     146             : 
     147             :         GC_BENCH_INC(zval_possible_root);
     148             : 
     149           0 :         if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
     150           0 :                 GC_ZVAL_SET_PURPLE(zv);
     151             : 
     152           0 :                 if (!GC_ZVAL_ADDRESS(zv)) {
     153           0 :                         gc_root_buffer *newRoot = GC_G(unused);
     154             : 
     155           0 :                         if (newRoot) {
     156           0 :                                 GC_G(unused) = newRoot->prev;
     157           0 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     158           0 :                                 newRoot = GC_G(first_unused);
     159           0 :                                 GC_G(first_unused)++;
     160             :                         } else {
     161           0 :                                 if (!GC_G(gc_enabled)) {
     162           0 :                                         GC_ZVAL_SET_BLACK(zv);
     163           0 :                                         return;
     164             :                                 }
     165           0 :                                 zv->refcount__gc++;
     166           0 :                                 gc_collect_cycles(TSRMLS_C);
     167           0 :                                 zv->refcount__gc--;
     168           0 :                                 newRoot = GC_G(unused);
     169           0 :                                 if (!newRoot) {
     170           0 :                                         return;
     171             :                                 }
     172           0 :                                 GC_ZVAL_SET_PURPLE(zv);
     173           0 :                                 GC_G(unused) = newRoot->prev;
     174             :                         }
     175             : 
     176           0 :                         newRoot->next = GC_G(roots).next;
     177           0 :                         newRoot->prev = &GC_G(roots);
     178           0 :                         GC_G(roots).next->prev = newRoot;
     179           0 :                         GC_G(roots).next = newRoot;
     180             : 
     181           0 :                         GC_ZVAL_SET_ADDRESS(zv, newRoot);
     182             : 
     183           0 :                         newRoot->handle = 0;
     184           0 :                         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           0 : ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
     194             : {
     195             :         struct _store_object *obj;
     196             : 
     197           0 :         if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_gc == NULL ||
     198             :             EG(objects_store).object_buckets == NULL)) {
     199           0 :                 return;
     200             :         }
     201             : 
     202             :         GC_BENCH_INC(zobj_possible_root);
     203             : 
     204           0 :         obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     205           0 :         if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
     206           0 :                 GC_SET_PURPLE(obj->buffered);
     207           0 :                 if (!GC_ADDRESS(obj->buffered)) {
     208           0 :                         gc_root_buffer *newRoot = GC_G(unused);
     209             : 
     210           0 :                         if (newRoot) {
     211           0 :                                 GC_G(unused) = newRoot->prev;
     212           0 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     213           0 :                                 newRoot = GC_G(first_unused);
     214           0 :                                 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           0 :                         newRoot->next = GC_G(roots).next;
     233           0 :                         newRoot->prev = &GC_G(roots);
     234           0 :                         GC_G(roots).next->prev = newRoot;
     235           0 :                         GC_G(roots).next = newRoot;
     236             : 
     237           0 :                         GC_SET_ADDRESS(obj->buffered, newRoot);
     238             : 
     239           0 :                         newRoot->handle = Z_OBJ_HANDLE_P(zv);
     240           0 :                         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           0 : ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC)
     250             : {
     251           0 :         gc_root_buffer* root_buffer = GC_ADDRESS(((zval_gc_info*)zv)->u.buffered);
     252             : 
     253           0 :         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           0 :         ((zval_gc_info*)zv)->u.buffered = NULL;
     267             : }
     268             : 
     269           0 : static void zval_scan_black(zval *pz TSRMLS_DC)
     270             : {
     271             :         Bucket *p;
     272             : 
     273             : tail_call:
     274           0 :         p = NULL;
     275           0 :         GC_ZVAL_SET_BLACK(pz);
     276             : 
     277           0 :         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     278             :                 zend_object_get_gc_t get_gc;
     279           0 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     280             : 
     281           0 :                 obj->refcount++;
     282           0 :                 if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
     283           0 :                         GC_SET_BLACK(obj->buffered);
     284           0 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     285             :                                      (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     286             :                                 int i, n;
     287             :                                 zval **table;
     288           0 :                                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     289             : 
     290           0 :                                 while (n > 0 && !table[n-1]) n--;
     291           0 :                                 for (i = 0; i < n; i++) {
     292           0 :                                         if (table[i]) {
     293           0 :                                                 pz = table[i];
     294           0 :                                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     295           0 :                                                         pz->refcount__gc++;
     296             :                                                 }
     297           0 :                                                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     298           0 :                                                         if (!props && i == n - 1) {
     299             :                                                                 goto tail_call;
     300             :                                                         } else {
     301           0 :                                                                 zval_scan_black(pz TSRMLS_CC);
     302             :                                                         }
     303             :                                                 }
     304             :                                         }
     305             :                                 }
     306           0 :                                 if (!props) {
     307           0 :                                         return;
     308             :                                 }
     309           0 :                                 p = props->pListHead;
     310             :                         }
     311             :                 }
     312           0 :         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     313           0 :                 if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     314           0 :                         p = Z_ARRVAL_P(pz)->pListHead;
     315             :                 }
     316             :         }
     317           0 :         while (p != NULL) {
     318           0 :                 pz = *(zval**)p->pData;
     319           0 :                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     320           0 :                         pz->refcount__gc++;
     321             :                 }
     322           0 :                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     323           0 :                         if (p->pListNext == NULL) {
     324           0 :                                 goto tail_call;
     325             :                         } else {
     326           0 :                                 zval_scan_black(pz TSRMLS_CC);
     327             :                         }
     328             :                 }
     329           0 :                 p = p->pListNext;
     330             :         }
     331             : }
     332             : 
     333           0 : static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
     334             : {
     335             :         Bucket *p;
     336             :         zend_object_get_gc_t get_gc;
     337             : 
     338           0 :         GC_SET_BLACK(obj->buffered);
     339           0 :         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     340             :                      (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     341             :                 int i, n;
     342             :                 zval **table;
     343           0 :                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     344             : 
     345           0 :                 for (i = 0; i < n; i++) {
     346           0 :                         if (table[i]) {
     347           0 :                                 pz = table[i];
     348           0 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     349           0 :                                         pz->refcount__gc++;
     350             :                                 }
     351           0 :                                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     352           0 :                                         zval_scan_black(pz TSRMLS_CC);
     353             :                                 }
     354             :                         }
     355             :                 }
     356           0 :                 if (!props) {
     357           0 :                         return;
     358             :                 }
     359           0 :                 p = props->pListHead;
     360           0 :                 while (p != NULL) {
     361           0 :                         pz = *(zval**)p->pData;
     362           0 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     363           0 :                                 pz->refcount__gc++;
     364             :                         }
     365           0 :                         if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     366           0 :                                 zval_scan_black(pz TSRMLS_CC);
     367             :                         }
     368           0 :                         p = p->pListNext;
     369             :                 }
     370             :         }
     371             : }
     372             : 
     373           0 : static void zval_mark_grey(zval *pz TSRMLS_DC)
     374             : {
     375             :         Bucket *p;
     376             : 
     377             : tail_call:
     378           0 :         if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
     379           0 :                 p = NULL;
     380             :                 GC_BENCH_INC(zval_marked_grey);
     381           0 :                 GC_ZVAL_SET_COLOR(pz, GC_GREY);
     382             : 
     383           0 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     384             :                         zend_object_get_gc_t get_gc;
     385           0 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     386             : 
     387           0 :                         obj->refcount--;
     388           0 :                         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     389             :                                 GC_BENCH_INC(zobj_marked_grey);
     390           0 :                                 GC_SET_COLOR(obj->buffered, GC_GREY);
     391           0 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     392             :                                              (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     393             :                                         int i, n;
     394             :                                         zval **table;
     395           0 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     396             : 
     397           0 :                                         while (n > 0 && !table[n-1]) n--;
     398           0 :                                         for (i = 0; i < n; i++) {
     399           0 :                                                 if (table[i]) {
     400           0 :                                                         pz = table[i];
     401           0 :                                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     402           0 :                                                                 pz->refcount__gc--;
     403             :                                                         }
     404           0 :                                                         if (!props && i == n - 1) {
     405             :                                                                 goto tail_call;
     406             :                                                         } else {
     407           0 :                                                                 zval_mark_grey(pz TSRMLS_CC);
     408             :                                                         }
     409             :                                                 }
     410             :                                         }
     411           0 :                                         if (!props) {
     412           0 :                                                 return;
     413             :                                         }
     414           0 :                                         p = props->pListHead;
     415             :                                 }
     416             :                         }
     417           0 :                 } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     418           0 :                         if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     419           0 :                                 GC_ZVAL_SET_BLACK(pz);
     420             :                         } else {
     421           0 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     422             :                         }
     423             :                 }
     424           0 :                 while (p != NULL) {
     425           0 :                         pz = *(zval**)p->pData;
     426           0 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     427           0 :                                 pz->refcount__gc--;
     428             :                         }
     429           0 :                         if (p->pListNext == NULL) {
     430           0 :                                 goto tail_call;
     431             :                         } else {
     432           0 :                                 zval_mark_grey(pz TSRMLS_CC);
     433             :                         }
     434           0 :                         p = p->pListNext;
     435             :                 }
     436             :         }
     437             : }
     438             : 
     439           0 : static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
     440             : {
     441             :         Bucket *p;
     442             :         zend_object_get_gc_t get_gc;
     443             : 
     444           0 :         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     445             :                 GC_BENCH_INC(zobj_marked_grey);
     446           0 :                 GC_SET_COLOR(obj->buffered, GC_GREY);
     447           0 :                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     448             :                              (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     449             :                         int i, n;
     450             :                         zval **table;
     451           0 :                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     452             : 
     453           0 :                         for (i = 0; i < n; i++) {
     454           0 :                                 if (table[i]) {
     455           0 :                                         pz = table[i];
     456           0 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     457           0 :                                                 pz->refcount__gc--;
     458             :                                         }
     459           0 :                                         zval_mark_grey(pz TSRMLS_CC);
     460             :                                 }
     461             :                         }
     462           0 :                         if (!props) {
     463           0 :                                 return;
     464             :                         }
     465           0 :                         p = props->pListHead;
     466           0 :                         while (p != NULL) {
     467           0 :                                 pz = *(zval**)p->pData;
     468           0 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     469           0 :                                         pz->refcount__gc--;
     470             :                                 }
     471           0 :                                 zval_mark_grey(pz TSRMLS_CC);
     472           0 :                                 p = p->pListNext;
     473             :                         }
     474             :                 }
     475             :         }
     476             : }
     477             : 
     478           0 : static void gc_mark_roots(TSRMLS_D)
     479             : {
     480           0 :         gc_root_buffer *current = GC_G(roots).next;
     481             : 
     482           0 :         while (current != &GC_G(roots)) {
     483           0 :                 if (current->handle) {
     484           0 :                         if (EG(objects_store).object_buckets) {
     485           0 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     486             : 
     487           0 :                                 if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
     488             :                                         zval z;
     489             : 
     490           0 :                                         INIT_PZVAL(&z);
     491           0 :                                         Z_OBJ_HANDLE(z) = current->handle;
     492           0 :                                         Z_OBJ_HT(z) = current->u.handlers;
     493           0 :                                         zobj_mark_grey(obj, &z TSRMLS_CC);
     494             :                                 } else {
     495           0 :                                         GC_SET_ADDRESS(obj->buffered, NULL);
     496             :                                         GC_REMOVE_FROM_BUFFER(current);
     497             :                                 }
     498             :                         }
     499             :                 } else {
     500           0 :                         if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
     501           0 :                                 zval_mark_grey(current->u.pz TSRMLS_CC);
     502             :                         } else {
     503           0 :                                 GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     504             :                                 GC_REMOVE_FROM_BUFFER(current);
     505             :                         }
     506             :                 }
     507           0 :                 current = current->next;
     508             :         }
     509           0 : }
     510             : 
     511           0 : static void zval_scan(zval *pz TSRMLS_DC)
     512             : {
     513             :         Bucket *p;
     514             : 
     515             : tail_call:      
     516           0 :         if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
     517           0 :                 p = NULL;
     518           0 :                 if (pz->refcount__gc > 0) {
     519           0 :                         zval_scan_black(pz TSRMLS_CC);
     520             :                 } else {
     521           0 :                         GC_ZVAL_SET_COLOR(pz, GC_WHITE);
     522           0 :                         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     523             :                                 zend_object_get_gc_t get_gc;
     524           0 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     525             : 
     526           0 :                                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     527           0 :                                         if (obj->refcount > 0) {
     528           0 :                                                 zobj_scan_black(obj, pz TSRMLS_CC);
     529             :                                         } else {
     530           0 :                                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     531           0 :                                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     532             :                                                              (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     533             :                                                         int i, n;
     534             :                                                         zval **table;
     535           0 :                                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     536             : 
     537           0 :                                                         while (n > 0 && !table[n-1]) n--;
     538           0 :                                                         for (i = 0; i < n; i++) {
     539           0 :                                                                 if (table[i]) {
     540           0 :                                                                         pz = table[i];
     541           0 :                                                                         if (!props && i == n - 1) {
     542             :                                                                                 goto tail_call;
     543             :                                                                         } else {
     544           0 :                                                                                 zval_scan(pz TSRMLS_CC);
     545             :                                                                         }
     546             :                                                                 }
     547             :                                                         }
     548           0 :                                                         if (!props) {
     549           0 :                                                                 return;
     550             :                                                         }
     551           0 :                                                         p = props->pListHead;
     552             :                                                 }
     553             :                                         }
     554             :                                 }
     555           0 :                         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     556           0 :                                 if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     557           0 :                                         GC_ZVAL_SET_BLACK(pz);
     558             :                                 } else {
     559           0 :                                         p = Z_ARRVAL_P(pz)->pListHead;
     560             :                                 }
     561             :                         }
     562             :                 }
     563           0 :                 while (p != NULL) {
     564           0 :                         if (p->pListNext == NULL) {
     565           0 :                                 pz = *(zval**)p->pData;
     566           0 :                                 goto tail_call;
     567             :                         } else {
     568           0 :                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     569             :                         }
     570           0 :                         p = p->pListNext;
     571             :                 }
     572             :         }
     573             : }
     574             : 
     575           0 : static void zobj_scan(zval *pz TSRMLS_DC)
     576             : {
     577             :         Bucket *p;
     578             :         zend_object_get_gc_t get_gc;
     579             : 
     580           0 :         if (EG(objects_store).object_buckets) {
     581           0 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     582             : 
     583           0 :                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     584           0 :                         if (obj->refcount > 0) {
     585           0 :                                 zobj_scan_black(obj, pz TSRMLS_CC);
     586             :                         } else {
     587           0 :                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     588           0 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     589             :                                              (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     590             :                                         int i, n;
     591             :                                         zval **table;
     592           0 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     593             : 
     594           0 :                                         for (i = 0; i < n; i++) {
     595           0 :                                                 if (table[i]) {
     596           0 :                                                         pz = table[i];
     597           0 :                                                         zval_scan(pz TSRMLS_CC);
     598             :                         }
     599             :                                         }
     600           0 :                                         if (!props) {
     601           0 :                                                 return;
     602             :                                         }
     603           0 :                                         p = props->pListHead;
     604           0 :                                         while (p != NULL) {
     605           0 :                                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     606           0 :                                                 p = p->pListNext;
     607             :                                         }
     608             :                                 }
     609             :                         }
     610             :                 }
     611             :         }
     612             : }
     613             : 
     614           0 : static void gc_scan_roots(TSRMLS_D)
     615             : {
     616           0 :         gc_root_buffer *current = GC_G(roots).next;
     617             : 
     618           0 :         while (current != &GC_G(roots)) {
     619           0 :                 if (current->handle) {
     620             :                         zval z;
     621             : 
     622           0 :                         INIT_PZVAL(&z);
     623           0 :                         Z_OBJ_HANDLE(z) = current->handle;
     624           0 :                         Z_OBJ_HT(z) = current->u.handlers;
     625           0 :                         zobj_scan(&z TSRMLS_CC);
     626             :                 } else {
     627           0 :                         zval_scan(current->u.pz TSRMLS_CC);
     628             :                 }
     629           0 :                 current = current->next;
     630             :         }
     631           0 : }
     632             : 
     633           0 : static void zval_collect_white(zval *pz TSRMLS_DC)
     634             : {
     635             :         Bucket *p;
     636             : 
     637             : tail_call:
     638           0 :         if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
     639           0 :                 p = NULL;
     640           0 :                 GC_ZVAL_SET_BLACK(pz);
     641             : 
     642           0 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     643             :                         zend_object_get_gc_t get_gc;
     644           0 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     645             : 
     646           0 :                         if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     647             :                                 /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     648           0 :                                 GC_SET_PURPLE(obj->buffered);
     649             : 
     650           0 :                                 if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     651             :                                              (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     652             :                                         int i, n;
     653             :                                         zval **table, *zv;
     654           0 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     655             : 
     656           0 :                                         if (!props) {
     657             :                                                 /* restore refcount and put into list to free */
     658           0 :                                                 pz->refcount__gc++;
     659           0 :                                                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     660           0 :                                                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     661             :                                         }
     662             : 
     663           0 :                                         while (n > 0 && !table[n-1]) n--;
     664           0 :                                         for (i = 0; i < n; i++) {
     665           0 :                                                 if (table[i]) {
     666           0 :                                                         zv = table[i];
     667           0 :                                                         if (Z_TYPE_P(zv) != IS_ARRAY || Z_ARRVAL_P(zv) != &EG(symbol_table)) {
     668           0 :                                                                 zv->refcount__gc++;
     669             :                                                         }
     670           0 :                                                         if (!props && i == n - 1) {
     671           0 :                                                                 pz = zv;
     672           0 :                                                                 goto tail_call;
     673             :                                                         } else {
     674           0 :                                                                 zval_collect_white(zv TSRMLS_CC);
     675             :                                                         }
     676             :                                                 }
     677             :                                         }
     678           0 :                                         if (!props) {
     679           0 :                                                 return;
     680             :                                         }
     681           0 :                                         p = props->pListHead;
     682             :                                 }
     683             :                         }
     684             :                 } else {
     685           0 :                         if (Z_TYPE_P(pz) == IS_ARRAY) {
     686           0 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     687             :                         }
     688             :                 }
     689             : 
     690             :                 /* restore refcount and put into list to free */
     691           0 :                 pz->refcount__gc++;
     692           0 :                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     693           0 :                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     694             : 
     695           0 :                 while (p != NULL) {
     696           0 :                         pz = *(zval**)p->pData;
     697           0 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     698           0 :                                 pz->refcount__gc++;
     699             :                         }
     700           0 :                         if (p->pListNext == NULL) {
     701           0 :                                 goto tail_call;
     702             :                         } else {
     703           0 :                                 zval_collect_white(pz TSRMLS_CC);
     704             :                         }
     705           0 :                         p = p->pListNext;
     706             :                 }
     707             :         }
     708             : }
     709             : 
     710           0 : static void zobj_collect_white(zval *pz TSRMLS_DC)
     711             : {
     712             :         Bucket *p;
     713             : 
     714           0 :         if (EG(objects_store).object_buckets) {
     715             :                 zend_object_get_gc_t get_gc;
     716           0 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     717             : 
     718           0 :                 if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     719             :                         /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     720           0 :                         GC_SET_PURPLE(obj->buffered);
     721             : 
     722           0 :                         if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
     723             :                                      (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
     724             :                                 int i, n;
     725             :                                 zval **table;
     726           0 :                                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     727             : 
     728           0 :                                 for (i = 0; i < n; i++) {
     729           0 :                                         if (table[i]) {
     730           0 :                                                 pz = table[i];
     731           0 :                                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     732           0 :                                                         pz->refcount__gc++;
     733             :                                                 }
     734           0 :                                                 zval_collect_white(pz TSRMLS_CC);
     735             :                                         }
     736             :                                 }
     737           0 :                                 if (!props) {
     738           0 :                                         return;
     739             :                                 }
     740           0 :                                 p = props->pListHead;
     741           0 :                                 while (p != NULL) {
     742           0 :                                         pz = *(zval**)p->pData;
     743           0 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     744           0 :                                                 pz->refcount__gc++;
     745             :                                         }
     746           0 :                                         zval_collect_white(pz TSRMLS_CC);
     747           0 :                                         p = p->pListNext;
     748             :                                 }
     749             :                         }
     750             :                 }
     751             :         }
     752             : }
     753             : 
     754           0 : static void gc_collect_roots(TSRMLS_D)
     755             : {
     756           0 :         gc_root_buffer *current = GC_G(roots).next;
     757             : 
     758           0 :         while (current != &GC_G(roots)) {
     759           0 :                 if (current->handle) {
     760           0 :                         if (EG(objects_store).object_buckets) {
     761           0 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     762             :                                 zval z;
     763             : 
     764           0 :                                 GC_SET_ADDRESS(obj->buffered, NULL);
     765           0 :                                 INIT_PZVAL(&z);
     766           0 :                                 Z_OBJ_HANDLE(z) = current->handle;
     767           0 :                                 Z_OBJ_HT(z) = current->u.handlers;
     768           0 :                                 zobj_collect_white(&z TSRMLS_CC);
     769             :                         }
     770             :                 } else {
     771           0 :                         GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     772           0 :                         zval_collect_white(current->u.pz TSRMLS_CC);
     773             :                 }
     774             : 
     775             :                 GC_REMOVE_FROM_BUFFER(current);
     776           0 :                 current = current->next;
     777             :         }
     778           0 : }
     779             : 
     780             : #define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
     781             : 
     782           0 : ZEND_API int gc_collect_cycles(TSRMLS_D)
     783             : {
     784           0 :         int count = 0;
     785             : 
     786           0 :         if (GC_G(roots).next != &GC_G(roots)) {
     787             :                 zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
     788             : 
     789           0 :                 if (GC_G(gc_active)) {
     790           0 :                         return 0;
     791             :                 }
     792           0 :                 GC_G(gc_runs)++;
     793           0 :                 GC_G(zval_to_free) = FREE_LIST_END;
     794           0 :                 GC_G(gc_active) = 1;
     795           0 :                 gc_mark_roots(TSRMLS_C);
     796           0 :                 gc_scan_roots(TSRMLS_C);
     797           0 :                 gc_collect_roots(TSRMLS_C);
     798             : 
     799           0 :                 orig_free_list = GC_G(free_list);
     800           0 :                 orig_next_to_free = GC_G(next_to_free);
     801           0 :                 p = GC_G(free_list) = GC_G(zval_to_free);
     802           0 :                 GC_G(zval_to_free) = NULL;
     803           0 :                 GC_G(gc_active) = 0;
     804             : 
     805             :                 /* First call destructors */
     806           0 :                 while (p != FREE_LIST_END) {
     807           0 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     808           0 :                                 if (EG(objects_store).object_buckets &&
     809           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     810           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
     811           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
     812           0 :                                         !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
     813             : 
     814           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
     815           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
     816           0 :                                         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);
     817           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
     818             :                                 }
     819             :                         }
     820           0 :                         count++;
     821           0 :                         p = p->u.next;
     822             :                 }
     823             : 
     824             :                 /* Destroy zvals */
     825           0 :                 p = GC_G(free_list);
     826           0 :                 while (p != FREE_LIST_END) {
     827           0 :                         GC_G(next_to_free) = p->u.next;
     828           0 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     829           0 :                                 if (EG(objects_store).object_buckets &&
     830           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     831           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
     832           0 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
     833           0 :                                         Z_TYPE(p->z) = IS_NULL;
     834           0 :                                         zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
     835             :                                 }
     836           0 :                         } else if (Z_TYPE(p->z) == IS_ARRAY) {
     837           0 :                                 Z_TYPE(p->z) = IS_NULL;
     838           0 :                                 zend_hash_destroy(Z_ARRVAL(p->z));
     839           0 :                                 FREE_HASHTABLE(Z_ARRVAL(p->z));
     840             :                         } else {
     841           0 :                                 zval_dtor(&p->z);
     842           0 :                                 Z_TYPE(p->z) = IS_NULL;
     843             :                         }
     844           0 :                         p = GC_G(next_to_free);
     845             :                 }
     846             : 
     847             :                 /* Free zvals */
     848           0 :                 p = GC_G(free_list);
     849           0 :                 while (p != FREE_LIST_END) {
     850           0 :                         q = p->u.next;
     851           0 :                         FREE_ZVAL_EX(&p->z);
     852           0 :                         p = q;
     853             :                 }
     854           0 :                 GC_G(collected) += count;
     855           0 :                 GC_G(free_list) = orig_free_list;
     856           0 :                 GC_G(next_to_free) = orig_next_to_free;
     857             :         }
     858             : 
     859           0 :         return count;
     860             : }
     861             : 
     862             : /*
     863             :  * Local variables:
     864             :  * tab-width: 4
     865             :  * c-basic-offset: 4
     866             :  * indent-tabs-mode: t
     867             :  * End:
     868             :  */

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:45 +0000 (7 days ago)

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