• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "checker/ETSchecker.h"
17 #include "evaluate/helpers.h"
18 
19 #include "evaluate/debugInfoDeserialization/debugInfoDeserializer.h"
20 #include "evaluate/scopedDebugInfoPlugin.h"
21 #include "evaluate/debugInfoStorage.h"
22 #include "evaluate/proxyProgramsCache.h"
23 #include "evaluate/entityDeclarator-inl.h"
24 
25 #include "libpandafile/class_data_accessor.h"
26 #include "libpandafile/file-inl.h"
27 
28 namespace ark::es2panda::evaluate {
29 
30 namespace {
31 
32 constexpr std::string_view OBJECT_NAME = "std.core.Object";
33 
GetFullSuperClassName(panda_file::ClassDataAccessor & cda)34 std::string GetFullSuperClassName(panda_file::ClassDataAccessor &cda)
35 {
36     return panda_file::ClassDataAccessor::DemangledName(cda.GetPandaFile().GetStringData(cda.GetSuperClassId()));
37 }
38 
GetSuperClassModuleAndClassName(panda_file::ClassDataAccessor & cda,DebugInfoStorage * debugInfoStorage)39 std::optional<std::pair<util::StringView, FileDebugInfo *>> GetSuperClassModuleAndClassName(
40     panda_file::ClassDataAccessor &cda, DebugInfoStorage *debugInfoStorage)
41 {
42     ASSERT(debugInfoStorage);
43 
44     auto fullSuperClassName = GetFullSuperClassName(cda);
45     if (fullSuperClassName == OBJECT_NAME) {
46         // Must stop iterating upon reaching std.core.Object.
47         return {};
48     }
49 
50     auto [moduleName, recordName] = helpers::SplitRecordName(fullSuperClassName);
51     auto *debugInfo = debugInfoStorage->GetDebugInfoByModuleName(moduleName);
52     if (UNLIKELY(debugInfo == nullptr)) {
53         LOG(FATAL, ES2PANDA) << "Failed to find debug info for module '" << moduleName << "'";
54     }
55     // Allocate record name for later usage in compilation.
56     return std::make_pair(util::UString(recordName, debugInfoStorage->Allocator()).View(), debugInfo);
57 }
58 
59 }  // namespace
60 
61 struct ChainEntryInfo final {
ChainEntryInfoark::es2panda::evaluate::ChainEntryInfo62     explicit ChainEntryInfo(std::string_view filePath, std::string_view declName,
63                             panda_file::ClassDataAccessor *accessor, parser::Program *prog)
64         : sourceFilePath(filePath), entityDeclarationName(declName), cda(accessor), program(prog)
65     {
66         ASSERT(cda != nullptr);
67     }
68 
69     DEFAULT_MOVE_SEMANTIC(ChainEntryInfo);
70     DEFAULT_COPY_SEMANTIC(ChainEntryInfo);
71 
72     ~ChainEntryInfo() = default;
73 
74     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
75     std::string_view sourceFilePath;
76     std::string_view entityDeclarationName;
77     // Pointer is required for move semantics.
78     panda_file::ClassDataAccessor *cda {nullptr};
79     parser::Program *program {nullptr};
80     // NOLINTEND(misc-non-private-member-variables-in-classes)
81 };
82 
GetSuperClass(panda_file::ClassDataAccessor & cda)83 ir::ETSTypeReference *DebugInfoDeserializer::GetSuperClass(panda_file::ClassDataAccessor &cda)
84 {
85     auto optClassInfo = GetSuperClassModuleAndClassName(cda, debugInfoPlugin_.GetDebugInfoStorage());
86     if (!optClassInfo) {
87         return nullptr;
88     }
89     auto [superClassName, debugInfo] = *optClassInfo;
90     return ResolveInheritanceChain(superClassName, debugInfo);
91 }
92 
ResolveInheritanceChain(util::StringView abcSuperName,FileDebugInfo * debugInfo)93 ir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChain(util::StringView abcSuperName,
94                                                                      FileDebugInfo *debugInfo)
95 {
96     ASSERT(debugInfo);
97 
98     auto *program = debugInfoPlugin_.GetProxyProgramsCache()->GetProgram(debugInfo->sourceFilePath);
99     if (debugInfoPlugin_.GetEntityDeclarator()->IsEntityDeclared(program, abcSuperName)) {
100         // If a superclass has already been declared, then we just need to create the TypeReference of it.
101         // Note that a TypeReference is created for each of usage of the super class.
102         return helpers::CreateETSTypeReference(debugInfoPlugin_.GetIrCheckHelper()->GetChecker(), abcSuperName);
103     }
104     return ResolveInheritanceChainImpl(abcSuperName, debugInfo);
105 }
106 
ResolveInheritanceChainImpl(util::StringView abcSuperName,FileDebugInfo * debugInfo)107 ir::ETSTypeReference *DebugInfoDeserializer::ResolveInheritanceChainImpl(util::StringView abcSuperName,
108                                                                          FileDebugInfo *debugInfo)
109 {
110     auto *checker = debugInfoPlugin_.GetIrCheckHelper()->GetChecker();
111 
112     // List starting from the most derived to the base class.
113     ArenaVector<ChainEntryInfo> chainEntryList(checker->Allocator()->Adapter());
114     auto alreadyCreatedSuperClassName = CollectChainInfo(chainEntryList, abcSuperName, debugInfo);
115 
116     ir::ETSTypeReference *superClass = nullptr;
117     if (!alreadyCreatedSuperClassName.Empty()) {
118         superClass = helpers::CreateETSTypeReference(checker, util::StringView(alreadyCreatedSuperClassName));
119     }
120 
121     auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
122     for (auto it = chainEntryList.rbegin(); it != chainEntryList.rend(); ++it) {
123         // Create entity in the same file in that it destinded to be declared, so import declaration should not be
124         // inserted in AST.
125         std::string_view declarationName = it->entityDeclarationName;
126         auto *cda = it->cda;
127         ASSERT(cda != nullptr);
128         // clang-format off
129         entityDeclarator->ImportGlobalEntity(it->sourceFilePath, declarationName, it->program, declarationName,
130             [this, superClass, cda](auto, auto *program, auto, auto name) {
131                 auto *classDecl = CreateClassDeclaration(name, *cda, superClass, program);
132                 return classDecl->Definition()->Ident()->Variable();
133             });
134         // clang-format on
135         superClass = helpers::CreateETSTypeReference(checker, declarationName);
136     }
137 
138     return superClass;
139 }
140 
CollectChainInfo(ArenaVector<ChainEntryInfo> & chainEntryList,util::StringView abcSuperName,FileDebugInfo * debugInfo)141 util::StringView DebugInfoDeserializer::CollectChainInfo(ArenaVector<ChainEntryInfo> &chainEntryList,
142                                                          util::StringView abcSuperName, FileDebugInfo *debugInfo)
143 {
144     ASSERT(debugInfo != nullptr);
145 
146     auto *proxyProgramsCache = debugInfoPlugin_.GetProxyProgramsCache();
147     auto *debugInfoStorage = debugInfoPlugin_.GetDebugInfoStorage();
148     auto *entityDeclarator = debugInfoPlugin_.GetEntityDeclarator();
149     auto *allocator = debugInfoPlugin_.GetIrCheckHelper()->GetChecker()->Allocator();
150 
151     // CC-OFFNXT(G.CTL.03) false positive
152     while (true) {
153         auto *program = proxyProgramsCache->GetProgram(debugInfo->sourceFilePath);
154         ASSERT(program != nullptr);
155         if (entityDeclarator->IsEntityDeclared(program, abcSuperName)) {
156             // Go until reach A_i, which has already been declared.
157             // Object <-- A_1 <-- ... <-- A_i <-- ... <-- A_n
158             //    |                        |
159             //    +------------------------+
160             //                |
161             //             Declared
162             return abcSuperName;
163         }
164 
165         // Class must be created - save necessary information about it.
166         auto classId = debugInfoStorage->FindClass(debugInfo->sourceFilePath, abcSuperName.Utf8());
167         if (!classId.IsValid()) {
168             LOG(FATAL, ES2PANDA) << "Can't find classId for " << abcSuperName;
169         }
170         auto *cda = allocator->New<panda_file::ClassDataAccessor>(*debugInfo->pf, classId);
171         chainEntryList.emplace_back(debugInfo->sourceFilePath, abcSuperName.Utf8(), cda, program);
172 
173         // Update information for the next iteration.
174         auto optClassInfo = GetSuperClassModuleAndClassName(*cda, debugInfoStorage);
175         if (!optClassInfo) {
176             // Go until reach Object:
177             // std.core.Object <-- A1 <-- A2 <-- ... <-- An
178             return "";
179         }
180         std::tie(abcSuperName, debugInfo) = *optClassInfo;
181     }
182 }
183 
184 }  // namespace ark::es2panda::evaluate
185