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 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::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 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; }