singrdk/base/Imported/Bartok/runtime/shared/GCs/PageTable.cs

809 lines
28 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
2008-03-05 09:52:00 -05:00
/*******************************************************************/
/* 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. */
/*******************************************************************/
namespace System.GCs {
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Bartok.Runtime;
#if SINGULARITY_KERNEL
using Microsoft.Singularity;
using Microsoft.Singularity.Memory;
using Sing_MemoryManager = Microsoft.Singularity.Memory.MemoryManager;
#elif SINGULARITY_PROCESS
using Microsoft.Singularity;
using Microsoft.Singularity.V1.Services;
#endif
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[AccessedByRuntime("referenced from brtforgc.asm/halforgc.asm")]
2008-03-05 09:52:00 -05:00
abstract internal class PageTable {
// WARNING: don't initialize any static fields in this class
// without manually running the class constructor at startup!
// The following are the several flavors for page table design:
// 1. Centralized: Only one table for all the memory. There are two
// cases within it: HIMEM or not. HIMEM forces the table to put beyond
// 4G. HIMEM means for correctness testing, not for performance.
// In both cases, an address is composed of two parts:
// (Page number) (offset in the page)
// 2. Otherwise: there are multiple page tables (DistributedPT). Two cases are allowed:
// (1) FlatDistributedPT: All the page tables manage the same-sized
// space. A page table itself is within the space it manages, and the
// offset of it to the starting address of the space is fixed.
// An address has three parts:
// (Segment number)(page number in the segment)(Offset in the page)
// Since a page table is located in a fixed offset of the segment it
// manages, we do not need a segment table. The segment number
// tells the segment address. With the fixed offset, we get the
// the page table.
// (2) two level hierarchy. An address has also three parts But
// each page table can be put at an arbitrary place. So we need a
// segment table to find the requested page table. Not implemented yet. But
// is straightforward based on the flat distributed page table.
// Note: to keep consistent with the previous central table, function Page()
// will return (segment number)(page number in the segment) as the page number.
// Note: In distributed case, pageTableCount refers to the total entries in all
// page tables that have already been allocated.
internal static UIntPtr pageTableCount;
#if SINGULARITY
2008-11-17 18:29:00 -05:00
public static UIntPtr baseAddr;
public static UIntPtr limitAddr;
2008-03-05 09:52:00 -05:00
#endif
[AccessedByRuntime("referenced from brtforgc.asm/halforgc.asm")]
internal static unsafe uint *halPageDescriptor;
[Intrinsic]
internal static PTType ptType;
2008-11-17 18:29:00 -05:00
#if SINGULARITY
internal const uint kernelProcessTag = 0x10000;
#endif
2008-03-05 09:52:00 -05:00
#if SINGULARITY_KERNEL
internal const uint ProcessPageMask = Sing_MemoryManager.ProcessPageMask;
internal static uint processTag;
internal static unsafe void Initialize()
{
Tracing.Log(Tracing.Debug, "Initialize.");
2008-11-17 18:29:00 -05:00
processTag = kernelProcessTag;
2008-03-05 09:52:00 -05:00
baseAddr = Sing_MemoryManager.KernelBaseAddr;
pageTableCount = Sing_MemoryManager.KernelPageCount;
2008-11-17 18:29:00 -05:00
limitAddr = baseAddr + (pageTableCount << PageBits);
2008-03-05 09:52:00 -05:00
halPageDescriptor = Sing_MemoryManager.KernelPageTable;
}
#elif SINGULARITY_PROCESS
internal const uint ProcessPageMask = 0xffff0000u;
internal static uint processTag;
internal static unsafe void Initialize()
{
Tracing.Log(Tracing.Debug, "Initialize.");
processTag = PageTableService.GetProcessTag();
baseAddr = PageTableService.GetBaseAddress();
pageTableCount = PageTableService.GetPageCount();
limitAddr = baseAddr + (pageTableCount << PageBits);
halPageDescriptor = PageTableService.GetPageTable();
}
#else
private static uint processTag {
get { VTable.NotReached("should not be using processTag outside of Singularity"); return 0; }
set { VTable.NotReached("should not be using processTag outside of Singularity"); }
}
// Initialization sets up page table in the memory. The pagetable must be
// set up before anything else (bootstrapmemory, GC,...) works.
// This function is implemented in each subclass by "new static", which
// is in general not ideal, but here since we explicitly call them by the class
// names, and they do not call other "new static" functions, there
// should not be any confusion.
// Also note that every function in this class that have different implementations
// in subclasses is implemented by testing ptType, and then calling the specific
// class. We cannot use the same idea as GC does, which use an "instance" of
// the specified GC type. The reason is that the instance needs allocate space
// from bootstrapmemory, which however, at each allocation, needs to change
// the pagetable. Since the pagetable has not generated an instance yet, the
// bootstrapmemory cannot access the pagetable through an instance.
[PreInitRefCounts]
[NoStackLinkCheck]
2008-11-17 18:29:00 -05:00
internal static void Initialize() {
2008-03-05 09:52:00 -05:00
switch(ptType) {
case PTType.CentralPT: {
CentralPT.Initialize();
break;
}
case PTType.CentralPTHimem: {
CentralPTHimem.Initialize();
break;
}
case PTType.FlatDistributedPT: {
FlatDistributedPT.Initialize();
break;
}
case PTType.FlatDistributedPTTest: {
FlatDistributedPTTest.Initialize();
break;
}
default: {
VTable.NotReached("Unknown PT type: "+ptType);
break;
}
}
}
#endif
[System.Diagnostics.Conditional("SINGULARITY")]
internal static void SetProcessTag(uint tag) {
processTag = tag;
}
internal static bool Dump(ushort process)
{
UIntPtr pages = (UIntPtr) 0;
UIntPtr freePages = UIntPtr.Zero;
UIntPtr usedPages = UIntPtr.Zero;
UIntPtr stackPages = UIntPtr.Zero;
UIntPtr fixedPages = UIntPtr.Zero;
UIntPtr sharedPages = UIntPtr.Zero;
UIntPtr unknownPages = UIntPtr.Zero;
for (UIntPtr i = (UIntPtr) 1; i < pageTableCount; i++) {
if (Process(i) != process) {
continue;
}
PageType type = Type(i);
pages++;
switch (type) {
case PageType.UnusedDirty:
case PageType.UnusedClean:
case PageType.Unallocated:
freePages++;
break;
case PageType.NonGC:
case PageType.System:
fixedPages++;
break;
case PageType.Stack:
stackPages++;
break;
case PageType.Shared:
sharedPages++;
break;
case PageType.Unknown:
unknownPages++;
break;
case PageType.Owner2:
case PageType.Owner3:
type = PageType.Owner2;
usedPages++;
break;
default:
usedPages++;
break;
}
}
if (pages > 0) {
VTable.DebugPrint("{0:d6}: free={1:d6}, use={2:d6}, stk={3:d6}, fix={4:d6}, shr={5:d6}, unk={6:d6}\n",
__arglist(process,
freePages,
usedPages,
stackPages,
fixedPages,
sharedPages,
unknownPages));
return true;
}
return false;
}
internal static void Dump(String s)
{
VTable.DebugPrint("PageTable.Dump({0}):\n",
__arglist(s));
ushort empty = 0;
for (ushort proc = 0; proc < 10240; proc++) {
if (Dump(proc)) {
empty = 0;
}
else {
empty++;
}
if (empty > 512) {
break;
}
}
Dump((ushort)0xffff);
PageType lastType = Type(UIntPtr.Zero);
ushort lastProcess = Process((UIntPtr) 1);
2008-11-17 18:29:00 -05:00
#if NOTHING
2008-03-05 09:52:00 -05:00
UIntPtr begin = UIntPtr.Zero;
2008-11-17 18:29:00 -05:00
#endif
2008-03-05 09:52:00 -05:00
UIntPtr freePages = UIntPtr.Zero;
UIntPtr usedPages = UIntPtr.Zero;
UIntPtr stackPages = UIntPtr.Zero;
UIntPtr fixedPages = UIntPtr.Zero;
UIntPtr sharedPages = UIntPtr.Zero;
UIntPtr unknownPages = UIntPtr.Zero;
for (UIntPtr i = (UIntPtr) 1; i < pageTableCount; i++) {
PageType type = Type(i);
switch (type) {
case PageType.UnusedDirty:
case PageType.UnusedClean:
case PageType.Unallocated:
freePages++;
break;
case PageType.NonGC:
case PageType.System:
fixedPages++;
break;
case PageType.Stack:
stackPages++;
break;
case PageType.Shared:
sharedPages++;
break;
case PageType.Unknown:
unknownPages++;
break;
case PageType.Owner2:
case PageType.Owner3:
type = PageType.Owner2;
usedPages++;
break;
default:
usedPages++;
break;
}
if ((type != lastType) || (Process(i) != lastProcess)) {
#if NOTHING
VTable.DebugPrint(" {0:x8}..{1:x8} ({2:d6} pages) : {3:x2} for {4:d5}\n",
__arglist(
((ulong)begin) << PageBits,
((ulong)i) << PageBits,
i - begin,
(uint)lastType,
lastProcess));
#endif
lastType = type;
lastProcess = Process(i);
2008-11-17 18:29:00 -05:00
#if NOTHING
2008-03-05 09:52:00 -05:00
begin = i;
2008-11-17 18:29:00 -05:00
#endif
2008-03-05 09:52:00 -05:00
}
}
#if NOTHING
VTable.DebugPrint(" {0:x8}..{1:x8} ({2:d6} pages) : {3:x2} for {4:d5}\n",
__arglist(
((ulong)begin) << PageBits,
((ulong)pageTableCount) << PageBits,
pageTableCount - begin,
(uint)lastType,
lastProcess));
#endif
VTable.DebugPrint(" =====: free={1:d6}, use={2:d6}, stk={3:d6}, fix={4:d6}, shr={5:d6}, unk={6:d6}\n",
__arglist(0,
freePages,
usedPages,
stackPages,
fixedPages,
sharedPages,
unknownPages));
}
internal static byte PageBits {
[Inline]
get { return 12; }
}
internal static UIntPtr PageSize {
[Inline]
get { return (UIntPtr)(1U << PageBits); }
}
internal static UIntPtr PageMask {
[Inline]
get { return PageSize - 1; }
}
internal static UIntPtr PageAlignMask {
[Inline]
get { return ~PageMask; }
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static PageType MyType(UIntPtr page) {
2008-03-05 09:52:00 -05:00
#if SINGULARITY
uint value = PageTableEntry(page);
if ((value & ProcessPageMask) == processTag) {
return (PageType)(value & 0xf);
}
else {
return PageType.Unknown;
}
#else
return Type(page);
#endif
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static PageType Type(UIntPtr page) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount, "page out of count");
return (PageType)(PageTableEntry(page) & 0xf);
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static void SetType(UIntPtr page, PageType newType) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
// for the Generational Collector, keep track of the max and min
// page of each generation.
switch(GC.gcType) {
#if !SINGULARITY || ADAPTIVE_COPYING_COLLECTOR || SEMISPACE_COLLECTOR || SLIDING_COLLECTOR
case GCType.AdaptiveCopyingCollector:
case GCType.SemispaceCollector:
case GCType.SlidingCollector:
int generation = (int)newType;
2008-11-17 18:29:00 -05:00
if (generation >= (int)GCs.GenerationalGCData.MIN_GENERATION
&& generation <= (int)GCs.GenerationalGCData.MAX_GENERATION)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
if (page < GCs.GenerationalGCData.MinGenPage[generation])
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
GCs.GenerationalGCData.MinGenPage[generation] = page;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
if (page > GCs.GenerationalGCData.MaxGenPage[generation])
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
GCs.GenerationalGCData.MaxGenPage[generation] = page;
2008-03-05 09:52:00 -05:00
}
}
break;
#endif
2008-11-17 18:29:00 -05:00
#if !SINGULARITY || MARK_SWEEP_COLLECTOR || CONCURRENT_MS_COLLECTOR || NULL_COLLECTOR
2008-03-05 09:52:00 -05:00
case GCType.MarkSweepCollector:
case GCType.TableMarkSweepCollector:
case GCType.ReferenceCountingCollector:
case GCType.ConcurrentMSCollector:
2008-11-17 18:29:00 -05:00
case GCType.CoCoMSCollector:
2008-03-05 09:52:00 -05:00
case GCType.AtomicRCCollector:
case GCType.DeferredReferenceCountingCollector:
case GCType.NullCollector:
// do nothing if not a Generational Collector
break;
#endif
default:
VTable.Assert(false, "Unknown Garbage Collector.");
break;
}
uint value = (PageTableEntry(page) & ~0xfU) | (uint)newType;
SetPageTableEntry(page, value);
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void VerifyType(UIntPtr page, PageType pageType)
{
VTable.Assert(PageTable.Type(page) == pageType);
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static uint Extra(UIntPtr page) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
2008-11-17 18:29:00 -05:00
uint result = (PageTableEntry(page) & 0xfff0U) >> 4;
VTable.Assert(((short) result)>=0);
return result;
2008-03-05 09:52:00 -05:00
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static void SetExtra(UIntPtr page, uint extra) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
2008-11-17 18:29:00 -05:00
VTable.Assert(extra <= 0xfff);
uint value = (PageTableEntry(page) & ~0xfff0U) | (extra << 4);
2008-03-05 09:52:00 -05:00
SetPageTableEntry(page, value);
}
[System.Diagnostics.Conditional("DEBUG")]
2008-11-17 18:29:00 -05:00
internal static void VerifyExtra(UIntPtr page, uint extra) {
2008-03-05 09:52:00 -05:00
VTable.Assert(Extra(page) == extra);
}
[Inline]
internal static ushort Process(UIntPtr page) {
#if SINGULARITY
VTable.Assert(page < pageTableCount);
return (ushort)((PageTableEntry(page) & 0xffff0000u) >> 16);
#else
return 0;
#endif
}
[Inline]
[System.Diagnostics.Conditional("SINGULARITY")]
2008-11-17 18:29:00 -05:00
internal static void SetProcess(UIntPtr page, ushort processId) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
uint value = (PageTableEntry(page) & ~0xffff0000U) | ((uint) processId << 16);
SetPageTableEntry(page, value);
}
#if SINGULARITY
[Inline]
2008-11-17 18:29:00 -05:00
private static uint ProcessTag(UIntPtr page) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
return PageTableEntry(page) & 0xffff0000u;
}
#endif
[Inline]
[System.Diagnostics.Conditional("SINGULARITY")]
2008-11-17 18:29:00 -05:00
private static void SetProcessTag(UIntPtr page, uint processTag) {
2008-03-05 09:52:00 -05:00
VTable.Assert(page < pageTableCount);
2008-11-17 18:29:00 -05:00
VTable.Assert(processTag > 0x0000ffffU);
2008-03-05 09:52:00 -05:00
uint value = (PageTableEntry(page) & ~0xffff0000U) | processTag;
SetPageTableEntry(page, value);
}
[Inline]
internal static void SetType(UIntPtr startPage,
UIntPtr pageCount,
PageType newType)
{
while (pageCount > UIntPtr.Zero) {
SetType(startPage, newType);
startPage++;
pageCount--;
}
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void VerifyType(UIntPtr startPage,
UIntPtr pageCount,
PageType pageType)
{
while (pageCount > UIntPtr.Zero) {
VerifyType(startPage, pageType);
startPage++;
pageCount--;
}
}
[Inline]
internal static void SetExtra(UIntPtr startPage,
UIntPtr pageCount,
2008-11-17 18:29:00 -05:00
uint extra)
2008-03-05 09:52:00 -05:00
{
while (pageCount > UIntPtr.Zero) {
SetExtra(startPage, extra);
startPage++;
pageCount--;
}
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void VerifyExtra(UIntPtr startPage,
UIntPtr pageCount,
2008-11-17 18:29:00 -05:00
uint extra)
2008-03-05 09:52:00 -05:00
{
while (pageCount > UIntPtr.Zero) {
VerifyExtra(startPage, extra);
startPage++;
pageCount--;
}
}
[Inline]
[System.Diagnostics.Conditional("SINGULARITY")]
internal static void SetProcess(UIntPtr startPage,
UIntPtr pageCount)
{
PageTable.SetProcessTag(startPage, pageCount, processTag);
}
[Inline]
[System.Diagnostics.Conditional("SINGULARITY")]
internal static void SetProcess(UIntPtr startPage,
UIntPtr pageCount,
ushort processId)
{
while (pageCount > UIntPtr.Zero) {
SetProcess(startPage, processId);
startPage++;
pageCount--;
}
}
[Inline]
[System.Diagnostics.Conditional("SINGULARITY")]
internal static void SetProcessTag(UIntPtr startPage,
UIntPtr pageCount,
uint processTag)
{
while (pageCount > UIntPtr.Zero) {
SetProcessTag(startPage, processTag);
startPage++;
pageCount--;
}
}
[Inline]
internal static bool IsGcPage(UIntPtr page)
{
return IsGcPage(Type(page));
}
[Inline]
internal static bool IsMyGcPage(UIntPtr page) {
return (PageTable.IsMyPage(page) && PageTable.IsGcPage(page));
}
// NOTE: The following 5 functions are dependent on the definition of
// System.GCs.PageType.
[Inline]
internal static bool IsGcPage(PageType pageType) {
return pageType >= PageType.Owner0;
}
[Inline]
internal static bool IsZombiePage(PageType pageType) {
return (pageType & PageType.TypeMask) == PageType.ZombieMask;
}
[Inline]
internal static bool IsLiveGcPage(PageType pageType) {
return ( (pageType >= PageType.Owner0) && (pageType < PageType.ZombieMask));
}
[Inline]
internal static PageType ZombieToLive(PageType pageType)
{
VTable.Assert(IsZombiePage(pageType), "not a zombie page");
PageType type = (PageType)(pageType - PageType.Zombie);
return type;
}
[Inline]
internal static PageType LiveToZombie(PageType pageType)
{
VTable.Assert(IsLiveGcPage(pageType), "not a live GC page");
return (pageType | PageType.Zombie);
}
// End of PageType dependent functions
[Inline]
internal static bool IsNonGcPage(PageType pageType) {
return pageType == PageType.NonGC;
}
[Inline]
internal static bool IsStackPage(PageType pageType) {
return pageType == PageType.Stack;
}
[Inline]
internal static bool IsSystemPage(PageType pageType) {
return pageType == PageType.System;
}
[Inline]
internal static bool IsSharedPage(PageType pageType) {
return pageType == PageType.Shared;
}
[Inline]
internal static bool IsUnknownPage(PageType pageType) {
return pageType == PageType.Unknown;
}
[Inline]
internal static bool IsUnallocatedPage(PageType pageType) {
return pageType == PageType.Unallocated;
}
[Inline]
internal static bool IsUnusedPage(UIntPtr page) {
return IsUnusedPageType(PageTable.Type(page));
}
[Inline]
internal static bool IsUnusedPageType(PageType pageType) {
return (pageType == PageType.UnusedDirty ||
pageType == PageType.UnusedClean);
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static bool IsMyPage(UIntPtr page) {
2008-03-05 09:52:00 -05:00
#if SINGULARITY
return PageTable.ProcessTag(page) == processTag;
#else
return true;
#endif
}
2008-11-17 18:29:00 -05:00
#if SINGULARITY
[Inline]
internal static bool IsKernelPage(UIntPtr page) {
return PageTable.ProcessTag(page) == kernelProcessTag;
}
#endif
2008-03-05 09:52:00 -05:00
[Inline]
internal static bool IsForeignAddr(UIntPtr addr) {
#if SINGULARITY
return (addr < baseAddr) || (addr >= limitAddr);
#else
return false;
#endif
}
[Inline]
internal static UIntPtr Page(UIntPtr addr) {
#if SINGULARITY
VTable.Assert((addr >= baseAddr) && (addr < limitAddr));
return (addr - baseAddr) >> PageBits;
#else
return (addr >> PageBits);
#endif
}
2008-11-17 18:29:00 -05:00
[Inline]
internal static bool IsAddrOnPage(UIntPtr addr, UIntPtr page) {
#if SINGULARITY
return ((addr - baseAddr) >> PageBits) == page;
#else
return (addr >> PageBits) == page;
#endif
}
2008-03-05 09:52:00 -05:00
[Inline]
internal static UIntPtr PageCount(UIntPtr size) {
return ((size + PageMask) >> PageBits);
}
[Inline]
internal static UIntPtr PageAddr(UIntPtr page) {
#if SINGULARITY
return ((page << PageBits) + baseAddr);
#else
return (page << PageBits);
#endif
}
[Inline]
internal static UIntPtr RegionSize(UIntPtr pageCount) {
return (pageCount << PageBits);
}
[Inline]
internal static bool PageAligned(UIntPtr addr) {
return ((addr & PageMask) == UIntPtr.Zero);
}
[Inline]
internal static UIntPtr PageAlign(UIntPtr addr) {
return addr & PageAlignMask;
}
[Inline]
internal static UIntPtr PagePad(UIntPtr addr) {
return ((addr + PageMask) & ~PageMask);
}
[Inline]
internal static UIntPtr PadBytesToPages(UIntPtr size)
{
return ((size + PageSize - 1) >> PageBits);
}
// The following functions have an implementation in each specific subclass. To avoid
// any potential "new static" confusion, we have the names with "Impl" suffix.
[Inline]
2008-11-17 18:29:00 -05:00
internal static uint PageTableEntry(UIntPtr page)
2008-03-05 09:52:00 -05:00
{
switch(ptType) {
case PTType.CentralPT:
case PTType.CentralPTHimem:
return CentralPT.PageTableEntryImpl(page);
#if !SINGULARITY
case PTType.FlatDistributedPT:
case PTType.FlatDistributedPTTest:
return FlatDistributedPT.PageTableEntryImpl(page);
#endif
default: {
VTable.NotReached("Unknown PT type: "+ptType);
return 0xffffffff;
}
}
}
[Inline]
2008-11-17 18:29:00 -05:00
internal static void SetPageTableEntry(UIntPtr page, uint value)
2008-03-05 09:52:00 -05:00
{
switch(ptType) {
case PTType.CentralPT:
case PTType.CentralPTHimem: {
CentralPT.SetPageTableEntryImpl(page, value);
break;
}
#if !SINGULARITY
case PTType.FlatDistributedPT:
case PTType.FlatDistributedPTTest: {
FlatDistributedPT.SetPageTableEntryImpl(page, value);
break;
}
#endif
default: {
VTable.NotReached("Unknown PT type: "+ptType);
break;
}
}
}
2008-11-17 18:29:00 -05:00
internal static void CreateNewPageTablesIfNecessary(UIntPtr startPage,
UIntPtr pageCount)
2008-03-05 09:52:00 -05:00
{
#if !SINGULARITY
if (ptType == PTType.FlatDistributedPT ||ptType == PTType.FlatDistributedPTTest) {
FlatDistributedPT.CreateNewPageTablesIfNecessaryImpl(startPage, pageCount);
}
#endif
}
[Inline]
internal static unsafe bool ValidMemAddress(void* addr)
{
#if !SINGULARITY
if (ptType == PTType.CentralPTHimem) {
return CentralPTHimem.ValidMemAddressImpl(addr);
}
#endif
return true;
}
}
}