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: 424 440 96.4 %
Date: 2014-08-04 Functions: 21 21 100.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       21298 : static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
      34             : {
      35       21298 :         if (gc_globals->buf) {
      36       21297 :                 free(gc_globals->buf);
      37       21297 :                 gc_globals->buf = NULL;
      38             :         }       
      39       21298 : }
      40             : 
      41       21265 : static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
      42             : {
      43       21265 :         gc_globals->gc_enabled = 0;
      44       21265 :         gc_globals->gc_active = 0;
      45             : 
      46       21265 :         gc_globals->buf = NULL;
      47             : 
      48       21265 :         gc_globals->roots.next = &gc_globals->roots;
      49       21265 :         gc_globals->roots.prev = &gc_globals->roots;
      50       21265 :         gc_globals->unused = NULL;
      51       21265 :         gc_globals->zval_to_free = NULL;
      52       21265 :         gc_globals->free_list = NULL;
      53       21265 :         gc_globals->next_to_free = NULL;
      54             : 
      55       21265 :         gc_globals->gc_runs = 0;
      56       21265 :         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       21265 : }
      71             : 
      72       21265 : 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       21265 :         gc_globals_ctor_ex(&gc_globals);
      78             : #endif
      79       21265 : }
      80             : 
      81       21298 : ZEND_API void gc_globals_dtor(TSRMLS_D)
      82             : {
      83             : #ifndef ZTS
      84       21298 :         root_buffer_dtor(&gc_globals TSRMLS_DC);
      85             : #endif
      86       21298 : }
      87             : 
      88       42486 : ZEND_API void gc_reset(TSRMLS_D)
      89             : {
      90       42486 :         GC_G(gc_runs) = 0;
      91       42486 :         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       42486 :         GC_G(roots).next = &GC_G(roots);
     107       42486 :         GC_G(roots).prev = &GC_G(roots);
     108             : 
     109       42486 :         if (GC_G(buf)) {
     110       42484 :                 GC_G(unused) = NULL;
     111       42484 :                 GC_G(first_unused) = GC_G(buf);
     112             : 
     113       42484 :                 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       42486 : }
     120             : 
     121       21277 : ZEND_API void gc_init(TSRMLS_D)
     122             : {
     123       21277 :         if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
     124       21264 :                 GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
     125       21264 :                 GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
     126       21264 :                 gc_reset(TSRMLS_C);
     127             :         }
     128       21277 : }
     129             : 
     130     7060104 : ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
     131             : {
     132     7394588 :         if (UNEXPECTED(GC_G(free_list) != NULL &&
     133             :                        GC_ZVAL_ADDRESS(zv) != NULL &&
     134             :                            GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
     135      167286 :                            (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
     136      167198 :                             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      167286 :                 return;
     140             :         }
     141             : 
     142     6892818 :         if (zv->type == IS_OBJECT) {
     143     2756761 :                 GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
     144     2756761 :                 return;
     145             :         }
     146             : 
     147             :         GC_BENCH_INC(zval_possible_root);
     148             : 
     149     4136057 :         if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
     150     1283240 :                 GC_ZVAL_SET_PURPLE(zv);
     151             : 
     152     1283240 :                 if (!GC_ZVAL_ADDRESS(zv)) {
     153     1283240 :                         gc_root_buffer *newRoot = GC_G(unused);
     154             : 
     155     1283240 :                         if (newRoot) {
     156     1113137 :                                 GC_G(unused) = newRoot->prev;
     157      170103 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     158      170092 :                                 newRoot = GC_G(first_unused);
     159      170092 :                                 GC_G(first_unused)++;
     160             :                         } else {
     161          11 :                                 if (!GC_G(gc_enabled)) {
     162           8 :                                         GC_ZVAL_SET_BLACK(zv);
     163           8 :                                         return;
     164             :                                 }
     165           3 :                                 zv->refcount__gc++;
     166           3 :                                 gc_collect_cycles(TSRMLS_C);
     167           3 :                                 zv->refcount__gc--;
     168           3 :                                 newRoot = GC_G(unused);
     169           3 :                                 if (!newRoot) {
     170           0 :                                         return;
     171             :                                 }
     172           3 :                                 GC_ZVAL_SET_PURPLE(zv);
     173           3 :                                 GC_G(unused) = newRoot->prev;
     174             :                         }
     175             : 
     176     1283232 :                         newRoot->next = GC_G(roots).next;
     177     1283232 :                         newRoot->prev = &GC_G(roots);
     178     1283232 :                         GC_G(roots).next->prev = newRoot;
     179     1283232 :                         GC_G(roots).next = newRoot;
     180             : 
     181     1283232 :                         GC_ZVAL_SET_ADDRESS(zv, newRoot);
     182             : 
     183     1283232 :                         newRoot->handle = 0;
     184     1283232 :                         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     3325963 : ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
     194             : {
     195             :         struct _store_object *obj;
     196             : 
     197     3325963 :         if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_gc == NULL ||
     198             :             EG(objects_store).object_buckets == NULL)) {
     199          53 :                 return;
     200             :         }
     201             : 
     202             :         GC_BENCH_INC(zobj_possible_root);
     203             : 
     204     3325910 :         obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
     205     3325910 :         if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
     206     1268250 :                 GC_SET_PURPLE(obj->buffered);
     207     1268250 :                 if (!GC_ADDRESS(obj->buffered)) {
     208     1268250 :                         gc_root_buffer *newRoot = GC_G(unused);
     209             : 
     210     1268250 :                         if (newRoot) {
     211     1208949 :                                 GC_G(unused) = newRoot->prev;
     212       59301 :                         } else if (GC_G(first_unused) != GC_G(last_unused)) {
     213       59281 :                                 newRoot = GC_G(first_unused);
     214       59281 :                                 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     1268250 :                         newRoot->next = GC_G(roots).next;
     233     1268250 :                         newRoot->prev = &GC_G(roots);
     234     1268250 :                         GC_G(roots).next->prev = newRoot;
     235     1268250 :                         GC_G(roots).next = newRoot;
     236             : 
     237     1268250 :                         GC_SET_ADDRESS(obj->buffered, newRoot);
     238             : 
     239     1268250 :                         newRoot->handle = Z_OBJ_HANDLE_P(zv);
     240     1268250 :                         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     1242135 : ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC)
     250             : {
     251     1242135 :         gc_root_buffer* root_buffer = GC_ADDRESS(((zval_gc_info*)zv)->u.buffered);
     252             : 
     253     1242135 :         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     1242135 :         ((zval_gc_info*)zv)->u.buffered = NULL;
     267             : }
     268             : 
     269      149589 : static void zval_scan_black(zval *pz TSRMLS_DC)
     270             : {
     271             :         Bucket *p;
     272             : 
     273             : tail_call:
     274      149589 :         p = NULL;
     275      149589 :         GC_ZVAL_SET_BLACK(pz);
     276             : 
     277      159594 :         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     278             :                 zend_object_get_gc_t get_gc;
     279       24742 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     280             : 
     281       24742 :                 obj->refcount++;
     282       24742 :                 if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
     283       24741 :                         GC_SET_BLACK(obj->buffered);
     284       24741 :                         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       24741 :                                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     289             : 
     290       24741 :                                 while (n > 0 && !table[n-1]) n--;
     291       39478 :                                 for (i = 0; i < n; i++) {
     292       29474 :                                         if (table[i]) {
     293       29474 :                                                 pz = table[i];
     294       29474 :                                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     295       29474 :                                                         pz->refcount__gc++;
     296             :                                                 }
     297       29474 :                                                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     298       14737 :                                                         if (!props && i == n - 1) {
     299             :                                                                 goto tail_call;
     300             :                                                         } else {
     301           0 :                                                                 zval_scan_black(pz TSRMLS_CC);
     302             :                                                         }
     303             :                                                 }
     304             :                                         }
     305             :                                 }
     306       10004 :                                 if (!props) {
     307           0 :                                         return;
     308             :                                 }
     309       10004 :                                 p = props->pListHead;
     310             :                         }
     311             :                 }
     312      124847 :         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     313       14789 :                 if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     314       14789 :                         p = Z_ARRVAL_P(pz)->pListHead;
     315             :                 }
     316             :         }
     317      368264 :         while (p != NULL) {
     318      109522 :                 pz = *(zval**)p->pData;
     319      109522 :                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     320      109522 :                         pz->refcount__gc++;
     321             :                 }
     322      109522 :                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     323       84755 :                         if (p->pListNext == NULL) {
     324       10962 :                                 goto tail_call;
     325             :                         } else {
     326       73793 :                                 zval_scan_black(pz TSRMLS_CC);
     327             :                         }
     328             :                 }
     329       98560 :                 p = p->pListNext;
     330             :         }
     331             : }
     332             : 
     333      111999 : 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      111999 :         GC_SET_BLACK(obj->buffered);
     339      111999 :         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      111999 :                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     344             : 
     345      112006 :                 for (i = 0; i < n; i++) {
     346           7 :                         if (table[i]) {
     347           7 :                                 pz = table[i];
     348           7 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     349           7 :                                         pz->refcount__gc++;
     350             :                                 }
     351           7 :                                 if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     352           7 :                                         zval_scan_black(pz TSRMLS_CC);
     353             :                                 }
     354             :                         }
     355             :                 }
     356      111999 :                 if (!props) {
     357        2001 :                         return;
     358             :                 }
     359      109998 :                 p = props->pListHead;
     360      269994 :                 while (p != NULL) {
     361       49998 :                         pz = *(zval**)p->pData;
     362       49998 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     363       49998 :                                 pz->refcount__gc++;
     364             :                         }
     365       49998 :                         if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
     366       49998 :                                 zval_scan_black(pz TSRMLS_CC);
     367             :                         }
     368       49998 :                         p = p->pListNext;
     369             :                 }
     370             :         }
     371             : }
     372             : 
     373      605666 : static void zval_mark_grey(zval *pz TSRMLS_DC)
     374             : {
     375             :         Bucket *p;
     376             : 
     377             : tail_call:
     378      605666 :         if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
     379      357930 :                 p = NULL;
     380             :                 GC_BENCH_INC(zval_marked_grey);
     381      357930 :                 GC_ZVAL_SET_COLOR(pz, GC_GREY);
     382             : 
     383      456862 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     384             :                         zend_object_get_gc_t get_gc;
     385      113416 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     386             : 
     387      113416 :                         obj->refcount--;
     388      113416 :                         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     389             :                                 GC_BENCH_INC(zobj_marked_grey);
     390       14493 :                                 GC_SET_COLOR(obj->buffered, GC_GREY);
     391       14493 :                                 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       14493 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     396             : 
     397       14493 :                                         while (n > 0 && !table[n-1]) n--;
     398       28976 :                                         for (i = 0; i < n; i++) {
     399       28967 :                                                 if (table[i]) {
     400       28967 :                                                         pz = table[i];
     401       28967 :                                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     402       28967 :                                                                 pz->refcount__gc--;
     403             :                                                         }
     404       28967 :                                                         if (!props && i == n - 1) {
     405             :                                                                 goto tail_call;
     406             :                                                         } else {
     407       14483 :                                                                 zval_mark_grey(pz TSRMLS_CC);
     408             :                                                         }
     409             :                                                 }
     410             :                                         }
     411           9 :                                         if (!props) {
     412           0 :                                                 return;
     413             :                                         }
     414           9 :                                         p = props->pListHead;
     415             :                                 }
     416             :                         }
     417      244514 :                 } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     418      134447 :                         if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     419           1 :                                 GC_ZVAL_SET_BLACK(pz);
     420             :                         } else {
     421      134446 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     422             :                         }
     423             :                 }
     424      850255 :                 while (p != NULL) {
     425      297813 :                         pz = *(zval**)p->pData;
     426      297813 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     427      297812 :                                 pz->refcount__gc--;
     428             :                         }
     429      297813 :                         if (p->pListNext == NULL) {
     430      134450 :                                 goto tail_call;
     431             :                         } else {
     432      163363 :                                 zval_mark_grey(pz TSRMLS_CC);
     433             :                         }
     434      163363 :                         p = p->pListNext;
     435             :                 }
     436             :         }
     437             : }
     438             : 
     439      200921 : 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      200921 :         if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
     445             :                 GC_BENCH_INC(zobj_marked_grey);
     446      200921 :                 GC_SET_COLOR(obj->buffered, GC_GREY);
     447      200921 :                 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      200921 :                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     452             : 
     453      358744 :                         for (i = 0; i < n; i++) {
     454      157823 :                                 if (table[i]) {
     455      157823 :                                         pz = table[i];
     456      157823 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     457      157823 :                                                 pz->refcount__gc--;
     458             :                                         }
     459      157823 :                                         zval_mark_grey(pz TSRMLS_CC);
     460             :                                 }
     461             :                         }
     462      200921 :                         if (!props) {
     463       80911 :                                 return;
     464             :                         }
     465      120010 :                         p = props->pListHead;
     466      320030 :                         while (p != NULL) {
     467       80010 :                                 pz = *(zval**)p->pData;
     468       80010 :                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     469       80010 :                                         pz->refcount__gc--;
     470             :                                 }
     471       80010 :                                 zval_mark_grey(pz TSRMLS_CC);
     472       80010 :                                 p = p->pListNext;
     473             :                         }
     474             :                 }
     475             :         }
     476             : }
     477             : 
     478          65 : static void gc_mark_roots(TSRMLS_D)
     479             : {
     480          65 :         gc_root_buffer *current = GC_G(roots).next;
     481             : 
     482      243221 :         while (current != &GC_G(roots)) {
     483      243091 :                 if (current->handle) {
     484      202033 :                         if (EG(objects_store).object_buckets) {
     485      202033 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     486             : 
     487      202033 :                                 if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
     488             :                                         zval z;
     489             : 
     490      200921 :                                         INIT_PZVAL(&z);
     491      200921 :                                         Z_OBJ_HANDLE(z) = current->handle;
     492      200921 :                                         Z_OBJ_HT(z) = current->u.handlers;
     493      200921 :                                         zobj_mark_grey(obj, &z TSRMLS_CC);
     494             :                                 } else {
     495        1112 :                                         GC_SET_ADDRESS(obj->buffered, NULL);
     496             :                                         GC_REMOVE_FROM_BUFFER(current);
     497             :                                 }
     498             :                         }
     499             :                 } else {
     500       41058 :                         if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
     501       41053 :                                 zval_mark_grey(current->u.pz TSRMLS_CC);
     502             :                         } else {
     503           5 :                                 GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     504             :                                 GC_REMOVE_FROM_BUFFER(current);
     505             :                         }
     506             :                 }
     507      243091 :                 current = current->next;
     508             :         }
     509          65 : }
     510             : 
     511      495583 : static void zval_scan(zval *pz TSRMLS_DC)
     512             : {
     513             :         Bucket *p;
     514             : 
     515             : tail_call:      
     516      495583 :         if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
     517      247859 :                 p = NULL;
     518      247859 :                 if (pz->refcount__gc > 0) {
     519          92 :                         zval_scan_black(pz TSRMLS_CC);
     520             :                 } else {
     521      247767 :                         GC_ZVAL_SET_COLOR(pz, GC_WHITE);
     522      336663 :                         if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     523             :                                 zend_object_get_gc_t get_gc;
     524      103372 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     525             : 
     526      103372 :                                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     527       14483 :                                         if (obj->refcount > 0) {
     528           1 :                                                 zobj_scan_black(obj, pz TSRMLS_CC);
     529             :                                         } else {
     530       14482 :                                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     531       14482 :                                                 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       14482 :                                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     536             : 
     537       14482 :                                                         while (n > 0 && !table[n-1]) n--;
     538       28957 :                                                         for (i = 0; i < n; i++) {
     539       28951 :                                                                 if (table[i]) {
     540       28951 :                                                                         pz = table[i];
     541       28951 :                                                                         if (!props && i == n - 1) {
     542             :                                                                                 goto tail_call;
     543             :                                                                         } else {
     544       14475 :                                                                                 zval_scan(pz TSRMLS_CC);
     545             :                                                                         }
     546             :                                                                 }
     547             :                                                         }
     548           6 :                                                         if (!props) {
     549           0 :                                                                 return;
     550             :                                                         }
     551           6 :                                                         p = props->pListHead;
     552             :                                                 }
     553             :                                         }
     554             :                                 }
     555      144395 :                         } else if (Z_TYPE_P(pz) == IS_ARRAY) {
     556      134388 :                                 if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
     557           0 :                                         GC_ZVAL_SET_BLACK(pz);
     558             :                                 } else {
     559      134388 :                                         p = Z_ARRVAL_P(pz)->pListHead;
     560             :                                 }
     561             :                         }
     562             :                 }
     563      570125 :                 while (p != NULL) {
     564      237750 :                         if (p->pListNext == NULL) {
     565      134391 :                                 pz = *(zval**)p->pData;
     566      134391 :                                 goto tail_call;
     567             :                         } else {
     568      103359 :                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     569             :                         }
     570      103359 :                         p = p->pListNext;
     571             :                 }
     572             :         }
     573             : }
     574             : 
     575      200921 : static void zobj_scan(zval *pz TSRMLS_DC)
     576             : {
     577             :         Bucket *p;
     578             :         zend_object_get_gc_t get_gc;
     579             : 
     580      200921 :         if (EG(objects_store).object_buckets) {
     581      200921 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     582             : 
     583      200921 :                 if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
     584      200921 :                         if (obj->refcount > 0) {
     585      111998 :                                 zobj_scan_black(obj, pz TSRMLS_CC);
     586             :                         } else {
     587       88923 :                                 GC_SET_COLOR(obj->buffered, GC_WHITE);
     588       88923 :                                 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       88923 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     593             : 
     594      246739 :                                         for (i = 0; i < n; i++) {
     595      157816 :                                                 if (table[i]) {
     596      157816 :                                                         pz = table[i];
     597      157816 :                                                         zval_scan(pz TSRMLS_CC);
     598             :                         }
     599             :                                         }
     600       88923 :                                         if (!props) {
     601       78910 :                                                 return;
     602             :                                         }
     603       10013 :                                         p = props->pListHead;
     604       50039 :                                         while (p != NULL) {
     605       30013 :                                                 zval_scan(*(zval**)p->pData TSRMLS_CC);
     606       30013 :                                                 p = p->pListNext;
     607             :                                         }
     608             :                                 }
     609             :                         }
     610             :                 }
     611             :         }
     612             : }
     613             : 
     614          65 : static void gc_scan_roots(TSRMLS_D)
     615             : {
     616          65 :         gc_root_buffer *current = GC_G(roots).next;
     617             : 
     618      242104 :         while (current != &GC_G(roots)) {
     619      241974 :                 if (current->handle) {
     620             :                         zval z;
     621             : 
     622      200921 :                         INIT_PZVAL(&z);
     623      200921 :                         Z_OBJ_HANDLE(z) = current->handle;
     624      200921 :                         Z_OBJ_HT(z) = current->u.handlers;
     625      200921 :                         zobj_scan(&z TSRMLS_CC);
     626             :                 } else {
     627       41053 :                         zval_scan(current->u.pz TSRMLS_CC);
     628             :                 }
     629      241974 :                 current = current->next;
     630             :         }
     631          65 : }
     632             : 
     633      416665 : static void zval_collect_white(zval *pz TSRMLS_DC)
     634             : {
     635             :         Bucket *p;
     636             : 
     637             : tail_call:
     638      416665 :         if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
     639      208340 :                 p = NULL;
     640      208340 :                 GC_ZVAL_SET_BLACK(pz);
     641             : 
     642      282538 :                 if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
     643             :                         zend_object_get_gc_t get_gc;
     644       88674 :                         struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     645             : 
     646       88674 :                         if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     647             :                                 /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     648       14482 :                                 GC_SET_PURPLE(obj->buffered);
     649             : 
     650       14482 :                                 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       14482 :                                         HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     655             : 
     656       14482 :                                         if (!props) {
     657             :                                                 /* restore refcount and put into list to free */
     658       14476 :                                                 pz->refcount__gc++;
     659       14476 :                                                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     660       14476 :                                                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     661             :                                         }
     662             : 
     663       14482 :                                         while (n > 0 && !table[n-1]) n--;
     664       28957 :                                         for (i = 0; i < n; i++) {
     665       28951 :                                                 if (table[i]) {
     666       28951 :                                                         zv = table[i];
     667       28951 :                                                         if (Z_TYPE_P(zv) != IS_ARRAY || Z_ARRVAL_P(zv) != &EG(symbol_table)) {
     668       28951 :                                                                 zv->refcount__gc++;
     669             :                                                         }
     670       28951 :                                                         if (!props && i == n - 1) {
     671       14476 :                                                                 pz = zv;
     672       14476 :                                                                 goto tail_call;
     673             :                                                         } else {
     674       14475 :                                                                 zval_collect_white(zv TSRMLS_CC);
     675             :                                                         }
     676             :                                                 }
     677             :                                         }
     678           6 :                                         if (!props) {
     679           0 :                                                 return;
     680             :                                         }
     681           6 :                                         p = props->pListHead;
     682             :                                 }
     683             :                         }
     684             :                 } else {
     685      119666 :                         if (Z_TYPE_P(pz) == IS_ARRAY) {
     686      119657 :                                 p = Z_ARRVAL_P(pz)->pListHead;
     687             :                         }
     688             :                 }
     689             : 
     690             :                 /* restore refcount and put into list to free */
     691      193864 :                 pz->refcount__gc++;
     692      193864 :                 ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
     693      193864 :                 GC_G(zval_to_free) = (zval_gc_info*)pz;
     694             : 
     695      476358 :                 while (p != NULL) {
     696      208290 :                         pz = *(zval**)p->pData;
     697      208290 :                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     698      208289 :                                 pz->refcount__gc++;
     699             :                         }
     700      208290 :                         if (p->pListNext == NULL) {
     701      119660 :                                 goto tail_call;
     702             :                         } else {
     703       88630 :                                 zval_collect_white(pz TSRMLS_CC);
     704             :                         }
     705       88630 :                         p = p->pListNext;
     706             :                 }
     707             :         }
     708             : }
     709             : 
     710      200921 : static void zobj_collect_white(zval *pz TSRMLS_DC)
     711             : {
     712             :         Bucket *p;
     713             : 
     714      200921 :         if (EG(objects_store).object_buckets) {
     715             :                 zend_object_get_gc_t get_gc;
     716      200921 :                 struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
     717             : 
     718      200921 :                 if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
     719             :                         /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
     720       64192 :                         GC_SET_PURPLE(obj->buffered);
     721             : 
     722       64192 :                         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       64192 :                                 HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
     727             : 
     728      192550 :                                 for (i = 0; i < n; i++) {
     729      128358 :                                         if (table[i]) {
     730      128358 :                                                 pz = table[i];
     731      128358 :                                                 if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     732      128358 :                                                         pz->refcount__gc++;
     733             :                                                 }
     734      128358 :                                                 zval_collect_white(pz TSRMLS_CC);
     735             :                                         }
     736             :                                 }
     737       64192 :                                 if (!props) {
     738       64181 :                                         return;
     739             :                                 }
     740          11 :                                 p = props->pListHead;
     741       10035 :                                 while (p != NULL) {
     742       10013 :                                         pz = *(zval**)p->pData;
     743       10013 :                                         if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
     744       10013 :                                                 pz->refcount__gc++;
     745             :                                         }
     746       10013 :                                         zval_collect_white(pz TSRMLS_CC);
     747       10013 :                                         p = p->pListNext;
     748             :                                 }
     749             :                         }
     750             :                 }
     751             :         }
     752             : }
     753             : 
     754          65 : static void gc_collect_roots(TSRMLS_D)
     755             : {
     756          65 :         gc_root_buffer *current = GC_G(roots).next;
     757             : 
     758      242104 :         while (current != &GC_G(roots)) {
     759      241974 :                 if (current->handle) {
     760      200921 :                         if (EG(objects_store).object_buckets) {
     761      200921 :                                 struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
     762             :                                 zval z;
     763             : 
     764      200921 :                                 GC_SET_ADDRESS(obj->buffered, NULL);
     765      200921 :                                 INIT_PZVAL(&z);
     766      200921 :                                 Z_OBJ_HANDLE(z) = current->handle;
     767      200921 :                                 Z_OBJ_HT(z) = current->u.handlers;
     768      200921 :                                 zobj_collect_white(&z TSRMLS_CC);
     769             :                         }
     770             :                 } else {
     771       41053 :                         GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
     772       41053 :                         zval_collect_white(current->u.pz TSRMLS_CC);
     773             :                 }
     774             : 
     775             :                 GC_REMOVE_FROM_BUFFER(current);
     776      241974 :                 current = current->next;
     777             :         }
     778          65 : }
     779             : 
     780             : #define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
     781             : 
     782          68 : ZEND_API int gc_collect_cycles(TSRMLS_D)
     783             : {
     784          68 :         int count = 0;
     785             : 
     786          68 :         if (GC_G(roots).next != &GC_G(roots)) {
     787             :                 zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
     788             : 
     789          65 :                 if (GC_G(gc_active)) {
     790           0 :                         return 0;
     791             :                 }
     792          65 :                 GC_G(gc_runs)++;
     793          65 :                 GC_G(zval_to_free) = FREE_LIST_END;
     794          65 :                 GC_G(gc_active) = 1;
     795          65 :                 gc_mark_roots(TSRMLS_C);
     796          65 :                 gc_scan_roots(TSRMLS_C);
     797          65 :                 gc_collect_roots(TSRMLS_C);
     798             : 
     799          65 :                 orig_free_list = GC_G(free_list);
     800          65 :                 orig_next_to_free = GC_G(next_to_free);
     801          65 :                 p = GC_G(free_list) = GC_G(zval_to_free);
     802          65 :                 GC_G(zval_to_free) = NULL;
     803          65 :                 GC_G(gc_active) = 0;
     804             : 
     805             :                 /* First call destructors */
     806      208470 :                 while (p != FREE_LIST_END) {
     807      208340 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     808      443370 :                                 if (EG(objects_store).object_buckets &&
     809       88674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     810       88674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
     811       88674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
     812       88674 :                                         !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
     813             : 
     814       78674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
     815       78674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
     816       78674 :                                         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       78674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
     818             :                                 }
     819             :                         }
     820      208340 :                         count++;
     821      208340 :                         p = p->u.next;
     822             :                 }
     823             : 
     824             :                 /* Destroy zvals */
     825          65 :                 p = GC_G(free_list);
     826      208470 :                 while (p != FREE_LIST_END) {
     827      208340 :                         GC_G(next_to_free) = p->u.next;
     828      208340 :                         if (Z_TYPE(p->z) == IS_OBJECT) {
     829      256022 :                                 if (EG(objects_store).object_buckets &&
     830       88674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
     831       78674 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
     832       78673 :                                         EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
     833       78673 :                                         Z_TYPE(p->z) = IS_NULL;
     834       78673 :                                         zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
     835             :                                 }
     836      119666 :                         } else if (Z_TYPE(p->z) == IS_ARRAY) {
     837      119657 :                                 Z_TYPE(p->z) = IS_NULL;
     838      119657 :                                 zend_hash_destroy(Z_ARRVAL(p->z));
     839      119657 :                                 FREE_HASHTABLE(Z_ARRVAL(p->z));
     840             :                         } else {
     841           9 :                                 zval_dtor(&p->z);
     842           9 :                                 Z_TYPE(p->z) = IS_NULL;
     843             :                         }
     844      208340 :                         p = GC_G(next_to_free);
     845             :                 }
     846             : 
     847             :                 /* Free zvals */
     848          65 :                 p = GC_G(free_list);
     849      208470 :                 while (p != FREE_LIST_END) {
     850      208340 :                         q = p->u.next;
     851      208340 :                         FREE_ZVAL_EX(&p->z);
     852      208340 :                         p = q;
     853             :                 }
     854          65 :                 GC_G(collected) += count;
     855          65 :                 GC_G(free_list) = orig_free_list;
     856          65 :                 GC_G(next_to_free) = orig_next_to_free;
     857             :         }
     858             : 
     859          68 :         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 Mon, 04 Aug 2014 15:49:01 +0000 (25 days ago)

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