/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/ts_class_analysis.h" #include "ecmascript/ts_types/ts_type_accessor.h" namespace panda::ecmascript::kungfu { void TSClassAnalysis::Run() const { const JSThread *thread = tsManager_->GetThread(); std::set<GlobalTSTypeRef> &collectedGT = GetCollectedGT(); for (auto iter = collectedGT.begin(); iter != collectedGT.end();) { JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(*iter); if (tsType->IsUndefined()) { ++iter; continue; } ASSERT(tsType->IsTSClassType()); JSHandle<TSClassType> classType(tsType); if (CheckInitInfoOnInheritanceChain(*classType)) { AnalyzeProperties(thread, *classType); collectedGT.erase(iter++); } else { ++iter; } } } bool TSClassAnalysis::CheckInitInfoOnInheritanceChain(const TSClassType *classType) const { DISALLOW_GARBAGE_COLLECTION; if (!tsManager_->HasTSHClass(classType)) { return false; } // All extended class types and itself have completed initialization analysis. if (classType->IsBaseClassType()) { return classType->GetHasAnalysedInitialization(); } while (true) { if (!classType->GetHasAnalysedInitialization()) { return false; } if (classType->IsBaseClassType()) { break; } classType = tsManager_->GetExtendedClassType(classType); } return true; } bool TSClassAnalysis::HasEscapedThisOnSuper(const TSClassType *classType) const { DISALLOW_GARBAGE_COLLECTION; if (classType->IsBaseClassType()) { return false; } while (true) { classType = tsManager_->GetExtendedClassType(classType); if (classType->GetHasEscapedThisInConstructor()) { return true; } if (classType->IsBaseClassType()) { break; } } return false; } void TSClassAnalysis::AnalyzeProperties(const JSThread *thread, const TSClassType *classType) const { DISALLOW_GARBAGE_COLLECTION; // Using this in self constructor will not mark flag in initialization analysis. if (HasEscapedThisOnSuper(classType)) { return; } if (!classType->GetHasPassedSubtypingCheck()) { return; } GlobalTSTypeRef classGT = classType->GetGT(); int hclassIndex = tsManager_->GetHClassIndex(classGT); ASSERT(hclassIndex != -1); JSHClass *hclass = JSHClass::Cast(tsManager_->GetValueFromCache(hclassIndex).GetTaggedObject()); if (UNLIKELY(hclass->IsDictionaryMode())) { return; } LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject()); for (uint32_t index = 0; index < hclass->NumberOfProps(); ++index) { JSTaggedValue key = layout->GetKey(index); if (AnalyzePropertyOnSelf(thread, classType, key) || AnalyzePropertyOnSupers(thread, classType, key)) { layout->SetIsNotHole(thread, index); } } } bool TSClassAnalysis::AnalyzePropertyOnSelf(const JSThread *thread, const TSClassType *classType, JSTaggedValue key) const { DISALLOW_GARBAGE_COLLECTION; JSHandle<TSObjectType> instanceType(thread, classType->GetInstanceType()); JSHandle<TSObjLayoutInfo> tsLayout(thread, instanceType->GetObjLayoutInfo()); int index = tsLayout->GetElementIndexByKey(key); if (!TSObjLayoutInfo::IsValidIndex(index)) { return false; } TSFieldAttributes tsAttr(tsLayout->GetAttribute(index).GetInt()); return tsAttr.GetInitializedFlag(); } bool TSClassAnalysis::AnalyzePropertyOnSupers(const JSThread *thread, const TSClassType *classType, JSTaggedValue key) const { DISALLOW_GARBAGE_COLLECTION; if (classType->IsBaseClassType()) { return false; } TSClassType *type = tsManager_->GetExtendedClassType(classType); while (true) { if (AnalyzePropertyOnSelf(thread, type, key)) { return true; } if (type->IsBaseClassType()) { break; } type = tsManager_->GetExtendedClassType(type); } return false; } } // namespace panda::ecmascript::kungfu