/*******************************************************************/ /* WARNING */ /* This file should be identical in the Bartok and Singularity */ /* depots. Master copy resides in Bartok Depot. Changes should be */ /* made to Bartok Depot and propagated to Singularity Depot. */ /*******************************************************************/ // // Copyright (c) Microsoft Corporation. All rights reserved. // namespace System.GCs { using Microsoft.Bartok.Runtime; using System.Threading; using System.Runtime.CompilerServices; internal unsafe class WriteBarrierCMS : UniversalWriteBarrier { internal static WriteBarrierCMS instance; [PreInitRefCounts] internal static new void Initialize() { WriteBarrierCMS.instance = (WriteBarrierCMS) BootstrapMemory.Allocate(typeof(WriteBarrierCMS)); } [Inline] protected override Object AtomicSwapImpl(ref Object reference, Object value) { ReferenceCheck(Magic.toPointer(ref reference), value); UIntPtr resultAddr = Interlocked.Exchange(Magic.toPointer(ref reference), Magic.addressOf(value)); return Magic.fromAddress(resultAddr); } [Inline] protected override Object AtomicCompareAndSwapImpl(ref Object reference, Object newValue, Object comparand) { ReferenceCheck(Magic.toPointer(ref reference), newValue); UIntPtr resultAddr = Interlocked.CompareExchange(Magic.toPointer(ref reference), Magic.addressOf(newValue), Magic.addressOf(comparand)); return Magic.fromAddress(resultAddr); } [Inline] protected override void CloneImpl(Object srcObject, Object dstObject) { // There is no need to keep track of initial writes, so do nothing! CloneNoBarrier(srcObject, dstObject); } [Inline] protected override void WriteReferenceImpl(UIntPtr *location, Object value) { ReferenceCheck(location, value); *location = Magic.addressOf(value); } /// /// In the sliding views phase, where some threads may have /// scanned their roots and others have not, we need to ensure /// that both old and new values will be marked and scanned. /// In the tracing phase we only need to ensure that the old /// values are traced and marked, as the old values may be the /// only references to a part of the snapshot reachable object /// graph from the untraced part of the object graph. /// /// The memory location being modified /// The reference value to be written into /// the "addr" location [Inline] private static void ReferenceCheck(UIntPtr *addr, Object value) { #if !SINGULARITY || CONCURRENT_MS_COLLECTOR if (ConcurrentMSCollector.CurrentMarkingPhase == ConcurrentMSCollector.MarkingPhase.ComputingRoots) { UIntPtr oldValue = *addr; MarkIfNecessary(oldValue); MarkIfNecessary(Magic.addressOf(value)); } else if (ConcurrentMSCollector.CurrentMarkingPhase == ConcurrentMSCollector.MarkingPhase.Tracing) { UIntPtr oldValue = *addr; MarkIfNecessary(oldValue); } #endif // CONCURRENT_MS_COLLECTOR } /// /// Ensures that a reference value is going to be marked and /// scanned. /// /// The reference value that may need to /// be marked [RequiredByBartok] private static void MarkIfNecessary(UIntPtr value) { #if !SINGULARITY || CONCURRENT_MS_COLLECTOR if (PageTable.IsGcPage(PageTable.Page(value)) && (ThreadHeaderQueue.GcMark(Magic.fromAddress(value)) != ConcurrentMSCollector.markedColor)) { VTable.Assert(PageTable.IsMyPage(PageTable.Page(value))); Thread thread = Thread.CurrentThread; ThreadHeaderQueue.Push(thread, value, ConcurrentMSCollector.markedColor, ConcurrentMSCollector.unmarkedColor); } #endif // CONCURRENT_MS_COLLECTOR } internal static void EnterSnoopingPhase() { WriteBarrierCMS.isSnooping = true; } internal static void LeaveSnoopingPhase() { WriteBarrierCMS.isSnooping = false; } internal static bool InSnoopingPhase { get { return WriteBarrierCMS.isSnooping; } } /// /// Ensures that an object is going to be marked and scanned. /// /// The object that may need to be marked internal static void MarkObject(Object obj) { #if !SINGULARITY || CONCURRENT_MS_COLLECTOR MarkIfNecessary(Magic.addressOf(obj)); #endif // CONCURRENT_MS_COLLECTOR } private static bool isSnooping; } }