void SnapshotExtractor::MarkVisitVar(Js::Var var) { AssertMsg(var != nullptr, "I don't think this should happen but not 100% sure."); AssertMsg(Js::JavascriptOperators::GetTypeId(var) < Js::TypeIds_Limit || Js::RecyclableObject::FromVar(var)->CanHaveInterceptors(), "Not cool."); //We don't need to visit tagged things if(JsSupport::IsVarTaggedInline(var)) { return; } if(JsSupport::IsVarPrimitiveKind(var)) { if(this->m_marks.MarkAndTestAddr<MarkTableTag::PrimitiveObjectTag>(var)) { Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(var); this->MarkVisitType(obj->GetType()); } } else { AssertMsg(JsSupport::IsVarComplexKind(var), "Shouldn't be anything else"); if(this->m_marks.MarkAndTestAddr<MarkTableTag::CompoundObjectTag>(var)) { Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(var); //do this here instead of in mark visit type as it wants the dynamic object as well if(Js::DynamicType::Is(obj->GetTypeId())) { Js::DynamicObject* dynObj = Js::DynamicObject::FromVar(obj); if(dynObj->GetDynamicType()->GetTypeHandler()->IsDeferredTypeHandler()) { dynObj->GetDynamicType()->GetTypeHandler()->EnsureObjectReady(dynObj); } } this->MarkVisitType(obj->GetType()); this->m_worklist.Enqueue(obj); } } }
void RuntimeContextInfo::GatherKnownObjectToPathMap(Js::ScriptContext* ctx) { JsUtil::List<const Js::PropertyRecord*, HeapAllocator> propertyRecordList(&HeapAllocator::Instance); this->EnqueueRootPathObject(_u("global"), ctx->GetGlobalObject()); this->EnqueueRootPathObject(_u("null"), ctx->GetLibrary()->GetNull()); this->EnqueueRootPathObject(_u("undeclBlockVar"), Js::RecyclableObject::FromVar(ctx->GetLibrary()->GetUndeclBlockVar())); this->EnqueueRootPathObject(_u("_defaultAccessor"), ctx->GetLibrary()->GetDefaultAccessorFunction()); if(ctx->GetConfig()->IsErrorStackTraceEnabled()) { this->EnqueueRootPathObject(_u("_stackTraceAccessor"), ctx->GetLibrary()->GetStackTraceAccessorFunction()); } this->EnqueueRootPathObject(_u("_throwTypeErrorRestrictedPropertyAccessor"), ctx->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction()); if(ctx->GetConfig()->IsES6PromiseEnabled()) { this->EnqueueRootPathObject(_u("_identityFunction"), ctx->GetLibrary()->GetIdentityFunction()); this->EnqueueRootPathObject(_u("_throwerFunction"), ctx->GetLibrary()->GetThrowerFunction()); } // ArrayIteratorPrototype is not created when we have JsBuiltins, it it created on-demand only #ifdef ENABLE_JS_BUILTINS if (ctx->IsJsBuiltInEnabled()) { ctx->GetLibrary()->EnsureBuiltInEngineIsReady(); } #endif this->EnqueueRootPathObject(_u("_arrayIteratorPrototype"), ctx->GetLibrary()->GetArrayIteratorPrototype()); this->EnqueueRootPathObject(_u("_mapIteratorPrototype"), ctx->GetLibrary()->GetMapIteratorPrototype()); this->EnqueueRootPathObject(_u("_setIteratorPrototype"), ctx->GetLibrary()->GetSetIteratorPrototype()); this->EnqueueRootPathObject(_u("_stringIteratorPrototype"), ctx->GetLibrary()->GetStringIteratorPrototype()); this->EnqueueRootPathObject(_u("_generatorNextFunction"), ctx->GetLibrary()->EnsureGeneratorNextFunction()); this->EnqueueRootPathObject(_u("_generatorReturnFunction"), ctx->GetLibrary()->EnsureGeneratorReturnFunction()); this->EnqueueRootPathObject(_u("_generatorThrowFunction"), ctx->GetLibrary()->EnsureGeneratorThrowFunction()); this->EnqueueRootPathObject(_u("_generatorFunctionConstructor"), ctx->GetLibrary()->GetGeneratorFunctionConstructor()); this->EnqueueRootPathObject(_u("_asyncFunctionConstructor"), ctx->GetLibrary()->GetAsyncFunctionConstructor()); uint32 counter = 0; while(!this->m_worklist.Empty()) { Js::RecyclableObject* curr = this->m_worklist.Dequeue(); counter++; //// //Handle the standard properties for all object types //load propArray with all property names propertyRecordList.Clear(); LoadAndOrderPropertyNames(curr, propertyRecordList); //access each property and process the target objects as needed for(int32 i = 0; i < propertyRecordList.Count(); ++i) { const Js::PropertyRecord* precord = propertyRecordList.Item(i); Js::Var getter = nullptr; Js::Var setter = nullptr; if(curr->GetAccessors(precord->GetPropertyId(), &getter, &setter, ctx)) { if(getter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(getter)) { TTDAssert(Js::JavascriptFunction::Is(getter), "The getter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, getter, precord, _u(">")); } if(setter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(setter)) { TTDAssert(Js::JavascriptFunction::Is(setter), "The setter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, Js::RecyclableObject::FromVar(setter), precord, _u("<")); } } else { Js::Var pitem = nullptr; BOOL isproperty = Js::JavascriptOperators::GetOwnProperty(curr, precord->GetPropertyId(), &pitem, ctx, nullptr); TTDAssert(isproperty, "Not sure what went wrong."); this->EnqueueNewPathVarAsNeeded(curr, pitem, precord, nullptr); } } //shouldn't have any dynamic array valued properties if(Js::DynamicType::Is(curr->GetTypeId())) { Js::ArrayObject* parray = Js::DynamicObject::FromVar(curr)->GetObjectArray(); if(parray != nullptr) { this->EnqueueNewPathVarAsNeeded(curr, parray, _u("_object_array_")); } } Js::RecyclableObject* proto = curr->GetPrototype(); bool skipProto = (proto == nullptr) || Js::JavascriptOperators::IsUndefinedOrNullType(proto->GetTypeId()); if(!skipProto) { this->EnqueueNewPathVarAsNeeded(curr, proto, _u("_proto_")); } curr->ProcessCorePaths(); } SortDictIntoListOnNames<Js::RecyclableObject*>(this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString); SortDictIntoListOnNames<Js::FunctionBody*>(this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString); SortDictIntoListOnNames<Js::DebuggerScope*>(this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString); }