void ScriptContextTTD::GetLoadedSources(const JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>* onlyLiveTopLevelBodies, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelScriptLoad, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelNewFunction, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelEval)
    {
        TTDAssert(topLevelScriptLoad.Count() == 0 && topLevelNewFunction.Count() == 0 && topLevelEval.Count() == 0, "Should be empty when you call this.");

        for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext())
        {
            Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
            if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
            {
                topLevelScriptLoad.Add(iter.CurrentValue());
            }
        }

        for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext())
        {
            Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
            if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
            {
                topLevelNewFunction.Add(iter.CurrentValue());
            }
        }

        for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext())
        {
            Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
            if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
            {
                topLevelEval.Add(iter.CurrentValue());
            }
        }
    }
    void SnapshotExtractor::DoMarkWalk(const JsUtil::List<Js::Var, HeapAllocator>& roots, const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ctxs, ThreadContext* threadContext)
    {
        TTDTimer timer;
        double startTime = timer.Now();

        for(int32 i = 0; i < roots.Count(); ++i)
        {
            Js::Var root = roots.Item(i);
            this->MarkVisitVar(root);
        }

        while(!this->m_worklist.Empty())
        {
            Js::RecyclableObject* nobj = this->m_worklist.Dequeue();
            AssertMsg(JsSupport::IsVarComplexKind(nobj), "Should only be these two options");

            this->MarkVisitStandardProperties(nobj);
            nobj->MarkVisitKindSpecificPtrs(this);
        }

        //Mark all of the well known objects/types
        for(int32 i = 0; i < ctxs.Count(); ++i)
        {
            ctxs.Item(i)->TTDWellKnownInfo->MarkWellKnownObjects_TTD(this->m_marks);
        }

        double endTime = timer.Now();
        this->m_pendingSnap->MarkTime = (endTime - startTime) / 1000.0;
    }
    void SnapshotExtractor::BeginSnapshot(ThreadContext* threadContext, const JsUtil::List<Js::Var, HeapAllocator>& roots, const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ctxs)
    {
        AssertMsg((this->m_pendingSnap == nullptr) & this->m_worklist.Empty(), "Something went wrong.");

        this->m_pendingSnap = HeapNew(SnapShot);

        UnorderedArrayList<NSSnapValues::SnapContext, TTD_ARRAY_LIST_SIZE_XSMALL>& snpCtxs = this->m_pendingSnap->GetContextList();
        for(int32 i = 0; i < ctxs.Count(); ++i)
        {
            NSSnapValues::SnapContext* snpCtx = snpCtxs.NextOpenEntry();
            NSSnapValues::ExtractScriptContext(snpCtx, ctxs.Item(i), this->m_pendingSnap->GetSnapshotSlabAllocator());
        }
    }
    void ThreadContextTTD::ClearContextsForSnapRestore(JsUtil::List<FinalizableObject*, HeapAllocator>& deadCtxs)
    {
        for(int32 i = 0; i < this->m_contextList.Count(); ++i)
        {
            Js::ScriptContext* ctx = this->m_contextList.Item(i);
            FinalizableObject* externalCtx = this->m_ttdContextToExternalRefMap.Item(ctx);

            deadCtxs.Add(externalCtx);
        }
        this->m_ttdContextToExternalRefMap.Clear();
        this->m_contextList.Clear();

        this->m_activeContext = nullptr;
    }
    void RuntimeContextInfo::LoadAndOrderPropertyNames(Js::RecyclableObject* obj, JsUtil::List<const Js::PropertyRecord*, HeapAllocator>& propertyList)
    {
        TTDAssert(propertyList.Count() == 0, "This should be empty.");

        Js::ScriptContext* ctx = obj->GetScriptContext();
        uint32 propcount = (uint32)obj->GetPropertyCount();

        //get all of the properties
        for(uint32 i = 0; i < propcount; ++i)
        {
            Js::PropertyIndex propertyIndex = (Js::PropertyIndex)i;
            Js::PropertyId propertyId = obj->GetPropertyId(propertyIndex);

            if((propertyId != Js::Constants::NoProperty) & (!Js::IsInternalPropertyId(propertyId)))
            {
                TTDAssert(obj->HasOwnProperty(propertyId), "We are assuming this is own property count.");

                propertyList.Add(ctx->GetPropertyName(propertyId));
            }
        }

        //now sort the list so the traversal order is stable
        //Rock a custom shell sort!!!!
        const int32 gaps[6] = { 132, 57, 23, 10, 4, 1 };

        int32 llen = propertyList.Count();
        for(uint32 gapi = 0; gapi < 6; ++gapi)
        {
            int32 gap = gaps[gapi];

            for(int32 i = gap; i < llen; i++)
            {
                const Js::PropertyRecord* temp = propertyList.Item(i);

                int32 j = 0;
                for(j = i; j >= gap && PropertyNameCmp(propertyList.Item(j - gap), temp); j -= gap)
                {
                    const Js::PropertyRecord* shiftElem = propertyList.Item(j - gap);
                    propertyList.SetItem(j, shiftElem);
                }

                propertyList.SetItem(j, temp);
            }
        }
    }
    void SnapshotExtractor::EvacuateMarkedIntoSnapshot(ThreadContext* threadContext, const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ctxs)
    {
        TTDTimer timer;
        double startTime = timer.Now();

        SnapShot* snap = this->m_pendingSnap;
        SlabAllocator& alloc = this->m_pendingSnap->GetSnapshotSlabAllocator();

        //We extract all the global code function bodies with the context so clear their marks now
        JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelScriptLoad(&HeapAllocator::Instance);
        JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelNewFunction(&HeapAllocator::Instance);
        JsUtil::List<TopLevelFunctionInContextRelation, HeapAllocator> topLevelEval(&HeapAllocator::Instance);

        for(int32 i = 0; i < ctxs.Count(); ++i)
        {
            topLevelScriptLoad.Clear();
            topLevelNewFunction.Clear();
            topLevelEval.Clear();

            Js::ScriptContext* ctx = ctxs.Item(i);
            ctx->TTDContextInfo->GetLoadedSources(topLevelScriptLoad, topLevelNewFunction, topLevelEval);

            for(int32 j = 0; j < topLevelScriptLoad.Count(); ++j)
            {
                Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(topLevelScriptLoad.Item(j).ContextSpecificBodyPtrId);
                this->m_marks.ClearMark(body);
            }

            for(int32 j = 0; j < topLevelNewFunction.Count(); ++j)
            {
                Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(topLevelNewFunction.Item(j).ContextSpecificBodyPtrId);
                this->m_marks.ClearMark(body);
            }

            for(int32 j = 0; j < topLevelEval.Count(); ++j)
            {
                Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(topLevelEval.Item(j).ContextSpecificBodyPtrId);
                this->m_marks.ClearMark(body);
            }
        }

        this->m_idToHandlerMap.Initialize(this->m_marks.GetCountForTag<MarkTableTag::TypeHandlerTag>());
        this->m_idToTypeMap.Initialize(this->m_marks.GetCountForTag<MarkTableTag::TypeTag>());

        //walk all the marked objects
        this->m_marks.InitializeIter();
        MarkTableTag tag = this->m_marks.GetTagValue();
        while(tag != MarkTableTag::Clear)
        {
            switch(tag & MarkTableTag::AllKindMask)
            {
            case MarkTableTag::TypeHandlerTag:
                this->ExtractHandlerIfNeeded(this->m_marks.GetPtrValue<Js::DynamicTypeHandler*>(), threadContext);
                break;
            case MarkTableTag::TypeTag:
                this->ExtractTypeIfNeeded(this->m_marks.GetPtrValue<Js::Type*>(), threadContext);
                break;
            case MarkTableTag::PrimitiveObjectTag:
            {
                this->ExtractTypeIfNeeded(this->m_marks.GetPtrValue<Js::RecyclableObject*>()->GetType(), threadContext);
                NSSnapValues::ExtractSnapPrimitiveValue(snap->GetNextAvailablePrimitiveObjectEntry(), this->m_marks.GetPtrValue<Js::RecyclableObject*>(), this->m_marks.GetTagValueIsWellKnown(), this->m_idToTypeMap, alloc);
                break;
            }
            case MarkTableTag::CompoundObjectTag:
            {
                this->ExtractTypeIfNeeded(this->m_marks.GetPtrValue<Js::RecyclableObject*>()->GetType(), threadContext);
                if(Js::ScriptFunction::Is(this->m_marks.GetPtrValue<Js::RecyclableObject*>()))
                {
                    this->ExtractScriptFunctionEnvironmentIfNeeded(this->m_marks.GetPtrValue<Js::ScriptFunction*>());
                }
                NSSnapObjects::ExtractCompoundObject(snap->GetNextAvailableCompoundObjectEntry(), this->m_marks.GetPtrValue<Js::RecyclableObject*>(), this->m_marks.GetTagValueIsWellKnown(), this->m_idToTypeMap, alloc);
                break;
            }
            case MarkTableTag::FunctionBodyTag:
                NSSnapValues::ExtractFunctionBodyInfo(snap->GetNextAvailableFunctionBodyResolveInfoEntry(), this->m_marks.GetPtrValue<Js::FunctionBody*>(), this->m_marks.GetTagValueIsWellKnown(), alloc);
                break;
            case MarkTableTag::EnvironmentTag:
            case MarkTableTag::SlotArrayTag:
                break; //should be handled with the associated script function
            default:
                AssertMsg(false, "If this isn't true then we have an unknown tag");
                break;
            }

            this->m_marks.MoveToNextAddress();
            tag = this->m_marks.GetTagValue();
        }

        double endTime = timer.Now();
        snap->ExtractTime = (endTime - startTime) / 1000.0;
    }