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 "resolveDepsRelation.h"
17
18 #include <util/commonUtil.h>
19
20 namespace panda::es2panda::aot {
21
CollectCommonjsAndJsonRecords(const std::vector<panda::pandasm::Field> & fieldList,const std::string & progKey,const std::string & recordName)22 bool DepsRelationResolver::CollectCommonjsAndJsonRecords(const std::vector<panda::pandasm::Field> &fieldList,
23 const std::string &progKey, const std::string &recordName)
24 {
25 for (const auto &field: fieldList) {
26 if (field.name == util::JSON_FilE_CONTENT) {
27 resolvedDepsRelation_[progKey].insert(recordName);
28 return true;
29 }
30 if (field.name.find(util::IS_COMMONJS) == std::string::npos) {
31 continue;
32 }
33 ASSERT(field.metadata->GetValue().has_value());
34 ASSERT(field.type.GetId() == panda_file::Type::TypeId::U8);
35 if (field.metadata->GetValue().value().GetValue<uint8_t>() > 0) {
36 resolvedDepsRelation_[progKey].insert(recordName);
37 return true;
38 }
39 }
40 return false;
41 }
42
FillRecord2ProgramMap(std::unordered_map<std::string,std::string> & record2ProgramMap)43 void DepsRelationResolver::FillRecord2ProgramMap(std::unordered_map<std::string, std::string> &record2ProgramMap)
44 {
45 for (const auto &progInfo : progsInfo_) {
46 for (const auto &record : progInfo.second->program.record_table) {
47 if (record.second.field_list.empty()) {
48 continue;
49 }
50 if (progInfo.first.find(util::NPM_ENTRIES) != std::string::npos) {
51 resolvedDepsRelation_[progInfo.first].insert(record.second.name);
52 continue;
53 }
54
55 // All commonjs files will be include as dependencies for compilation without resolve. Since commonjs files
56 // will only have commonjs as dependencies, there'll be no dependencies missing.
57 if (CollectCommonjsAndJsonRecords(record.second.field_list, progInfo.first, record.second.name)) {
58 break;
59 }
60 record2ProgramMap[record.second.name] = progInfo.first;
61 }
62 }
63 }
64
CollectDepsIfNeeded(const std::string & ohmurl)65 void DepsRelationResolver::CollectDepsIfNeeded(const std::string &ohmurl)
66 {
67 if (ohmurl.find(util::NORMALIZED_OHMURL_NOT_SO) != std::string::npos &&
68 !util::IsExternalPkgNames(ohmurl, compileContextInfo_.externalPkgNames)) {
69 std::string collectRecord = util::GetRecordNameFromNormalizedOhmurl(ohmurl);
70 if (!collectRecord.empty() && this->resolvedRecords_.count(collectRecord) == 0) {
71 this->depsToBeResolved_.push(collectRecord);
72 this->resolvedRecords_.insert(collectRecord);
73 }
74 }
75 }
76
DumpDepsRelations()77 void DepsRelationResolver::DumpDepsRelations()
78 {
79 auto &ss = std::cout;
80 ss << "All Dependency Files:" << std::endl;
81 for (auto dep : resolvedDepsRelation_) {
82 auto fileName = dep.first;
83 size_t abcFileNameSeparatorPos = dep.first.rfind(util::CHAR_VERTICAL_LINE);
84 size_t pos = dep.first.rfind(util::SLASH_TAG, abcFileNameSeparatorPos);
85 if (pos != std::string::npos) {
86 fileName = dep.first.substr(pos + 1, abcFileNameSeparatorPos - pos - 1);
87 }
88 ss << "program_file: " << fileName << std::endl;
89 for (auto r : dep.second) {
90 ss << "record_name: " << r << std::endl;
91 }
92 }
93 ss << std::endl;
94 }
95
Resolve()96 bool DepsRelationResolver::Resolve()
97 {
98 std::unordered_map<std::string, std::string> record2ProgramMap {};
99 FillRecord2ProgramMap(record2ProgramMap);
100
101 for (auto &entryRecord : compileContextInfo_.compileEntries) {
102 depsToBeResolved_.push(entryRecord);
103 resolvedRecords_.insert(entryRecord);
104
105 while (!depsToBeResolved_.empty()) {
106 auto record = depsToBeResolved_.front();
107 depsToBeResolved_.pop();
108 const auto progkeyItr = record2ProgramMap.find(record);
109 if (progkeyItr == record2ProgramMap.end()) {
110 // Skip external record, may happen at PatchFix or HSP scenario
111 continue;
112 }
113 const auto progItr = progsInfo_.find(progkeyItr->second);
114 if (progItr == progsInfo_.end()) {
115 std::cerr << "Failed to find program for file: " << progkeyItr->second << std::endl;
116 return false;
117 }
118 resolvedDepsRelation_[progkeyItr->second].insert(record);
119
120 CollectStaticImportDepsRelation(progItr->second->program, record);
121 CollectDynamicImportDepsRelation(progItr->second->program, record);
122 }
123 }
124 if (dumpDepsInfo_) {
125 DumpDepsRelations();
126 }
127 return true;
128 }
129
CollectStaticImportDepsRelation(const panda::pandasm::Program & program,const std::string & recordName)130 void DepsRelationResolver::CollectStaticImportDepsRelation(const panda::pandasm::Program &program,
131 const std::string &recordName)
132 {
133 auto &recordTable = program.record_table;
134 std::string literalArrayKey;
135 for (auto &pair : recordTable) {
136 if (pair.first.find(recordName) == std::string::npos) {
137 continue;
138 }
139 util::VisitStaticImports<true>(program, pair.second, [this](const std::string &ohmurl) {
140 this->CollectDepsIfNeeded(ohmurl);
141 });
142 }
143 }
144
CollectDynamicImportDepsRelation(const panda::pandasm::Program & program,const std::string & recordName)145 void DepsRelationResolver::CollectDynamicImportDepsRelation(const panda::pandasm::Program &program,
146 const std::string &recordName)
147 {
148 for (const auto &func: program.function_table) {
149 if (func.second.name.find(recordName) == std::string::npos) {
150 continue;
151 }
152 util::VisitDyanmicImports<true>(func.second, [this](const std::string &ohmurl) {
153 this->CollectDepsIfNeeded(ohmurl);
154 });
155 }
156 }
157
158 } // namespace panda::es2panda::aot
159