Merge pull request #2803 from BrzVlad/feature-conc-pinned-scan
authormonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 14 Apr 2016 19:15:35 +0000 (20:15 +0100)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 14 Apr 2016 19:15:35 +0000 (20:15 +0100)
[sgen] Scan pinned objects in nursery as part of concurrent mark

Objects pinned in the nursery can hide behind them a large graph of objects in the heap which is never scanned because we don't follow references in the nursery. After precleaning, we scan the latest set of pinned objects (while locking in order to make sure that the set doesn't change, so none are moved).

1  2 
mono/sgen/sgen-gc.c
mono/sgen/sgen-pinning.c
mono/sgen/sgen-pinning.h

diff --combined mono/sgen/sgen-gc.c
index e6b8d672dce53fbb73037cc2c4dbfe39bca1a9a7,d9bc6485945160ff79c0fa85b20e1cddb4c10e4b..5ec907371f38451a493b5de735ff26c44620c6cf
   * Copyright 2011 Xamarin, Inc.
   * Copyright (C) 2012 Xamarin Inc
   *
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Library General Public
 - * License 2.0 as published by the Free Software Foundation;
 - *
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Library General Public License for more details.
 - *
 - * You should have received a copy of the GNU Library General Public
 - * License 2.0 along with this library; if not, write to the Free
 - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   *
   * Important: allocation provides always zeroed memory, having to do
   * a memset after allocation is deadly for performance.
@@@ -332,6 -343,7 +332,6 @@@ nursery_canaries_enabled (void
   * ######################################################################
   */
  MonoCoopMutex gc_mutex;
 -gboolean sgen_try_free_some_memory;
  
  #define SCAN_START_SIZE       SGEN_SCAN_START_SIZE
  
@@@ -696,6 -708,8 +696,8 @@@ pin_objects_from_nursery_pin_queue (gbo
                        definitely_pinned [count] = obj_to_pin;
                        count++;
                }
+               if (concurrent_collection_in_progress)
+                       sgen_pinning_register_pinned_in_nursery (obj_to_pin);
  
        next_pin_queue_entry:
                last = addr;
@@@ -1074,12 -1088,6 +1076,12 @@@ finish_gray_stack (int generation, Scan
        if (sgen_client_bridge_need_processing ())
                sgen_client_bridge_reset_data ();
  
 +      /*
 +       * Mark all strong toggleref objects. This must be done before we walk ephemerons or finalizers
 +       * to ensure they see the full set of live objects.
 +       */
 +      sgen_client_mark_togglerefs (start_addr, end_addr, ctx);
 +
        /*
         * Walk the ephemeron tables marking all values with reachable keys. This must be completely done
         * before processing finalizable objects and non-tracking weak links to avoid finalizing/clearing
                ++ephemeron_rounds;
        } while (!done_with_ephemerons);
  
 -      sgen_client_mark_togglerefs (start_addr, end_addr, ctx);
 -
        if (sgen_client_bridge_need_processing ()) {
                /*Make sure the gray stack is empty before we process bridge objects so we get liveness right*/
                sgen_drain_gray_stack (ctx);
@@@ -1411,6 -1421,8 +1413,8 @@@ job_mod_union_preclean (void *worker_da
  
        major_collector.scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
        sgen_los_scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
+       sgen_scan_pin_queue_objects (ctx);
  }
  
  static void
@@@ -1705,7 -1717,7 +1709,7 @@@ major_copy_or_mark_from_roots (size_t *
  
        sgen_client_pre_collection_checks ();
  
 -      if (!concurrent) {
 +      if (mode != COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
                /* Remsets are not useful for a major collection */
                remset.clear_cards ();
        }
@@@ -3008,6 -3020,7 +3012,7 @@@ sgen_gc_init (void
  
        alloc_nursery ();
  
+       sgen_pinning_init ();
        sgen_cement_init (cement_enabled);
  
        if ((env = g_getenv (MONO_GC_DEBUG_NAME))) {
@@@ -3179,7 -3192,11 +3184,7 @@@ sgen_gc_lock (void
  void
  sgen_gc_unlock (void)
  {
 -      gboolean try_free = sgen_try_free_some_memory;
 -      sgen_try_free_some_memory = FALSE;
        mono_coop_mutex_unlock (&gc_mutex);
 -      if (try_free)
 -              mono_thread_hazardous_try_free_some ();
  }
  
  void
@@@ -3246,6 -3263,8 +3251,6 @@@ sgen_restart_world (int generation, GGT
  
        binary_protocol_world_restarted (generation, sgen_timestamp ());
  
 -      sgen_try_free_some_memory = TRUE;
 -
        if (sgen_client_bridge_need_processing ())
                sgen_client_bridge_processing_finish (generation);
  
diff --combined mono/sgen/sgen-pinning.c
index eedd1f0343a93e720cac0838ec29ff70e8bd773e,85629f436ec46189ebd1aa7d8b30e8efdc9ad8c4..cfe3db1acd0167bd08d1c7e285b6313736460ec3
@@@ -5,7 -5,18 +5,7 @@@
   * Copyright 2003-2010 Novell, Inc.
   * Copyright (C) 2012 Xamarin Inc
   *
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Library General Public
 - * License 2.0 as published by the Free Software Foundation;
 - *
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Library General Public License for more details.
 - *
 - * You should have received a copy of the GNU Library General Public
 - * License 2.0 along with this library; if not, write to the Free
 - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  
  #include "config.h"
  
  static SgenPointerQueue pin_queue;
  static size_t last_num_pinned = 0;
+ /*
+  * While we hold the pin_queue_mutex, all objects in pin_queue_objs will
+  * stay pinned, which means they can't move, therefore they can be scanned.
+  */
+ static SgenPointerQueue pin_queue_objs;
+ static MonoCoopMutex pin_queue_mutex;
  
  #define PIN_HASH_SIZE 1024
  static void *pin_hash_filter [PIN_HASH_SIZE];
  
+ void
+ sgen_pinning_init (void)
+ {
+       mono_coop_mutex_init (&pin_queue_mutex);
+ }
  void
  sgen_init_pinning (void)
  {
+       mono_coop_mutex_lock (&pin_queue_mutex);
        memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
        pin_queue.mem_type = INTERNAL_MEM_PIN_QUEUE;
+       sgen_pointer_queue_clear (&pin_queue_objs);
  }
  
  void
@@@ -37,6 -62,27 +51,27 @@@ sgen_finish_pinning (void
  {
        last_num_pinned = pin_queue.next_slot;
        sgen_pointer_queue_clear (&pin_queue);
+       mono_coop_mutex_unlock (&pin_queue_mutex);
+ }
+ void
+ sgen_pinning_register_pinned_in_nursery (GCObject *obj)
+ {
+       sgen_pointer_queue_add (&pin_queue_objs, obj);
+ }
+ void
+ sgen_scan_pin_queue_objects (ScanCopyContext ctx)
+ {
+       int i;
+       ScanObjectFunc scan_func = ctx.ops->scan_object;
+       mono_coop_mutex_lock (&pin_queue_mutex);
+       for (i = 0; i < pin_queue_objs.next_slot; ++i) {
+               GCObject *obj = (GCObject *)pin_queue_objs.data [i];
+               scan_func (obj, sgen_obj_get_descriptor_safe (obj), ctx.queue);
+       }
+       mono_coop_mutex_unlock (&pin_queue_mutex);
  }
  
  void
diff --combined mono/sgen/sgen-pinning.h
index 00eb20dd819830f40a45a620981e812426673df2,92143c6ee60756871b3c0a3cf346b10a68349ab5..2ae2594fa85e1c762898e60d43e6caafaf0ed40a
@@@ -4,7 -4,18 +4,7 @@@
   * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
   * Copyright (C) 2012 Xamarin Inc
   *
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Library General Public
 - * License 2.0 as published by the Free Software Foundation;
 - *
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Library General Public License for more details.
 - *
 - * You should have received a copy of the GNU Library General Public
 - * License 2.0 along with this library; if not, write to the Free
 - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  #ifndef __MONO_SGEN_PINNING_H__
  #define __MONO_SGEN_PINNING_H__
@@@ -18,10 -29,13 +18,13 @@@ enum 
        PIN_TYPE_MAX
  };
  
+ void sgen_pinning_init (void);
  void sgen_pin_stage_ptr (void *ptr);
  void sgen_optimize_pin_queue (void);
  void sgen_init_pinning (void);
  void sgen_finish_pinning (void);
+ void sgen_pinning_register_pinned_in_nursery (GCObject *obj);
+ void sgen_scan_pin_queue_objects (ScanCopyContext ctx);
  void sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot);
  size_t sgen_get_pinned_count (void);
  void sgen_pinning_setup_section (GCMemSection *section);