Js::FunctionBody* ScriptContextTTD::FindRootBodyByTopLevelCtr(uint32 bodyCtrId) const { for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId) { return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); } } for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId) { return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); } } for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId) { return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); } } return nullptr; }
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 ScriptContextTTD::CleanUnreachableTopLevelBodies(const JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>& liveTopLevelBodies) { //don't clear top-level loaded bodies this->m_ttdTopLevelNewFunction.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_PTR_ID, TTD::TopLevelFunctionInContextRelation>& entry) -> bool { Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(entry.Value().ContextSpecificBodyPtrId); if(liveTopLevelBodies.Contains(body)) { return false; } else { this->ProcessFunctionBodyOnUnLoad(body, nullptr); return true; } }); this->m_ttdTopLevelEval.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_PTR_ID, TTD::TopLevelFunctionInContextRelation>& entry) -> bool { Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(entry.Value().ContextSpecificBodyPtrId); if(liveTopLevelBodies.Contains(body)) { return false; } else { this->ProcessFunctionBodyOnUnLoad(body, nullptr); return true; } }); }
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; }