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