internal unsafe void ScanHook(Object obj)
            {
                UIntPtr page = PageTable.Page(Magic.addressOf(obj));

                if (PageTable.Type(page) != SegregatedFreeList.SMALL_OBJ_PAGE)
                {
                    //VTable.DebugPrint("   not tagging because this isn't a small object page");
                    return;
                }
                SegregatedFreeList.PageHeader *ph =
                    (SegregatedFreeList.PageHeader *)PageTable.PageAddr(page);
                if (!new CoCoPageUserValue(ph->userValue).Marked)
                {
                    //VTable.DebugPrint("   not tagging because the page isn't marked\n");
                    return;
                }
                if (obj is EMU ||
                    obj is Monitor ||
                    obj is Thread ||
                    obj is ThreadHeaderQueue)
                {
                    CoCoBarrier.NotifyPin(Magic.addressOf(obj));
                    if (fVerbose)
                    {
                        VTable.DebugPrint("      $$ not tagging object because it's a monitor or EMU\n");
                    }
                    return;
                }
                if (doingCoCo)
                {
                    //VTable.DebugPrint("   not tagging object because doingCoCo\n");
                    return;
                }
                if (!CoCoBarrier.instance.ObjectIsNotCopied(obj))
                {
                    if (fVerbose)
                    {
                        VTable.DebugPrint("   not tagging object because object is already in the process of being copied.\n");
                    }
                    return;
                }

                if (fVerbose && obj.GetType() != typeof(Object))
                {
                    VTable.DebugPrint("    $$ tagging a non-System.Object; type is ");
                    VTable.DebugPrint(obj.GetType().Name);
                    VTable.DebugPrint("\n");
                }

                // REVIEW: I wish that there was an easier way of
                // doing this.
                Object copy;

                if (obj is Array)
                {
                    Array a = (Array)obj;
                    if (a.IsVector)
                    {
                        copy = GC.AllocateVector(a.vtable, a.Length);
                    }
                    else
                    {
                        copy = GC.AllocateArray(a.vtable, a.Rank, a.Length);
                    }
                }
                else if (obj is String)
                {
                    String s = (String)obj;
                    // REVIEW: this is not nice.
                    copy = GC.AllocateString(s.ArrayLength - 1);
                }
                else
                {
                    copy = GC.AllocateObject(obj.vtable);
                }

                VTable.Assert(ObjectLayout.Sizeof(copy)
                              == ObjectLayout.Sizeof(obj),
                              "Copy is not same size as original");

                spaceOverhead += ObjectLayout.Sizeof(copy);

                bool    first = !CoCoBarrier.instance.AnyTaggedForCopying;
                UIntPtr thisSpaceOverhead;

                if (CoCoBarrier.instance.TagObjectForCopy(obj, copy,
                                                          out thisSpaceOverhead))
                {
                    cnt++;
                    if (first)
                    {
                        lock (interlock) {
                            if (!wantCoCo && !doingCoCo)
                            {
                                wantCoCo = true;
                            }
                        }
                    }
                }

                spaceOverhead += thisSpaceOverhead;
            }