1 /** 2 * Copyright (c) 2021-2025 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 #ifndef PANDA_LINKER_CONTEXT_H 17 #define PANDA_LINKER_CONTEXT_H 18 19 #include <forward_list> 20 #include <functional> 21 22 #include "libpandafile/bytecode_instruction.h" 23 #include "libpandafile/file_items.h" 24 #include "libpandafile/file_reader.h" 25 #include "libpandafile/file_item_container.h" 26 27 #include "linker.h" 28 #include "macros.h" 29 30 namespace ark::static_linker { 31 32 class Context; 33 34 class CodePatcher { 35 public: 36 struct IndexedChange { 37 BytecodeInstruction inst; 38 panda_file::MethodItem *mi; 39 panda_file::IndexedItem *it; 40 }; 41 42 struct StringChange { 43 BytecodeInstruction inst; 44 std::string str; 45 panda_file::MethodItem *mi; 46 panda_file::StringItem *it {}; 47 }; 48 49 struct LiteralArrayChange { 50 BytecodeInstruction inst; 51 panda_file::LiteralArrayItem *old; 52 53 panda_file::LiteralArrayItem *it {}; 54 }; 55 56 using Change = 57 std::variant<IndexedChange, StringChange, LiteralArrayChange, std::string, std::function<bool(bool peek)>>; 58 59 void Add(Change c); 60 61 void ApplyDeps(Context *ctx); 62 63 void TryDeletePatch(); 64 void Patch(const std::pair<size_t, size_t> range); 65 void AddStringDependency(); 66 67 void Devour(CodePatcher &&p); 68 69 void AddRange(std::pair<size_t, size_t> range); 70 GetRanges()71 const std::vector<std::pair<size_t, size_t>> &GetRanges() const 72 { 73 return ranges_; 74 } 75 Clear()76 void Clear() 77 { 78 changes_.clear(); 79 ranges_.clear(); 80 } 81 GetSize()82 size_t GetSize() const 83 { 84 return changes_.size(); 85 } 86 87 private: 88 std::vector<Change> changes_; 89 std::vector<std::pair<size_t, size_t>> ranges_; 90 91 void ApplyLiteralArrayChange(LiteralArrayChange &lc, Context *ctx); 92 }; 93 94 struct CodeData { 95 std::vector<uint8_t> *code; 96 panda_file::MethodItem *omi; 97 panda_file::MethodItem *nmi; 98 const panda_file::FileReader *fileReader; 99 100 bool patchLnp; 101 }; 102 103 class Helpers { 104 public: 105 static std::vector<panda_file::Type> BreakProto(panda_file::ProtoItem *p); 106 }; 107 108 class Context { 109 public: 110 explicit Context(Config conf); 111 112 ~Context(); 113 114 NO_COPY_SEMANTIC(Context); 115 NO_MOVE_SEMANTIC(Context); 116 117 void Write(const std::string &out); 118 119 void Read(const std::vector<std::string> &input); 120 121 void Merge(); 122 123 void Parse(); 124 125 void ComputeLayout(); 126 127 void Patch(); 128 129 void TryDelete(); 130 GetKnownItems()131 const std::unordered_map<panda_file::BaseItem *, panda_file::BaseItem *> &GetKnownItems() const 132 { 133 return knownItems_; 134 } 135 GetContainer()136 panda_file::ItemContainer &GetContainer() 137 { 138 return cont_; 139 } 140 GetContainer()141 const panda_file::ItemContainer &GetContainer() const 142 { 143 return cont_; 144 } 145 GetResult()146 const Result &GetResult() const 147 { 148 return result_; 149 } 150 HasErrors()151 bool HasErrors() const 152 { 153 return !result_.errors.empty(); 154 } 155 156 private: 157 friend class CodePatcher; 158 159 Config conf_; 160 Result result_; 161 panda_file::ItemContainer cont_; 162 163 std::vector<std::function<void()>> deferredFailedAnnotations_; 164 165 std::vector<CodeData> codeDatas_; 166 CodePatcher patcher_; 167 168 std::forward_list<panda_file::FileReader> readers_; 169 std::unordered_map<panda_file::BaseItem *, panda_file::BaseItem *> knownItems_; 170 std::multimap<const panda_file::BaseItem *, const panda_file::FileReader *> cameFrom_; 171 size_t literalArrayId_ {}; 172 std::map<std::tuple<panda_file::BaseClassItem *, panda_file::StringItem *, panda_file::TypeItem *>, 173 panda_file::ForeignFieldItem *> 174 foreignFields_; 175 std::map<std::tuple<panda_file::BaseClassItem *, panda_file::StringItem *, panda_file::ProtoItem *, uint32_t>, 176 panda_file::ForeignMethodItem *> 177 foreignMethods_; 178 179 panda_file::BaseClassItem *ClassFromOld(panda_file::BaseClassItem *old); 180 181 panda_file::TypeItem *TypeFromOld(panda_file::TypeItem *old); 182 183 panda_file::StringItem *StringFromOld(const panda_file::StringItem *s); 184 185 static std::string GetStr(const panda_file::StringItem *si); 186 187 void MergeClass(const panda_file::FileReader *reader, panda_file::ClassItem *ni, panda_file::ClassItem *oi); 188 189 void AddRegularClasses(); 190 191 void CheckClassRedifinition(const std::string &name, panda_file::FileReader *reader); 192 193 void FillRegularClasses(); 194 195 void MergeMethod(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::MethodItem *oi); 196 197 void MergeField(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::FieldItem *oi); 198 199 void MergeForeignMethod(const panda_file::FileReader *reader, panda_file::ForeignMethodItem *fm); 200 201 void MergeForeignMethodCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz, 202 panda_file::ForeignMethodItem *fm); 203 204 void MergeForeignField(const panda_file::FileReader *reader, panda_file::ForeignFieldItem *ff); 205 206 void MergeForeignFieldCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz, 207 panda_file::ForeignFieldItem *ff); 208 209 std::pair<bool, bool> UpdateDebugInfo(panda_file::MethodItem *ni, panda_file::MethodItem *oi); 210 211 void CreateTryBlocks(panda_file::MethodItem *ni, panda_file::CodeItem *nci, panda_file::MethodItem *oi, 212 panda_file::CodeItem *oci); 213 214 bool IsSameProto(panda_file::ProtoItem *op1, panda_file::ProtoItem *op2); 215 216 template <typename T> 217 struct AddAnnotationImplData { 218 const panda_file::FileReader *reader; 219 T *ni; 220 T *oi; 221 size_t from; 222 size_t retriesLeft; 223 }; 224 225 template <typename T, typename Getter, typename Adder> 226 void AddAnnotationImpl(AddAnnotationImplData<T> ad, Getter getter, Adder adder); 227 228 template <typename T> 229 void TransferAnnotations(const panda_file::FileReader *reader, T *ni, T *oi); 230 231 std::pair<panda_file::ProtoItem *, std::vector<panda_file::MethodParamItem>> GetProto(panda_file::ProtoItem *p); 232 233 bool IsSameType(ark::panda_file::TypeItem *nevv, ark::panda_file::TypeItem *old); 234 235 void ProcessCodeData(CodePatcher &p, CodeData *data); 236 237 void MakeChangeWithId(CodePatcher &p, CodeData *data); 238 239 void HandleStringId(CodePatcher &p, const BytecodeInstruction &inst, const panda_file::File *filePtr, 240 CodeData *data); 241 242 void HandleLiteralArrayId(CodePatcher &p, const BytecodeInstruction &inst, const panda_file::File *filePtr, 243 const std::map<panda_file::File::EntityId, panda_file::BaseItem *> *items); 244 245 void AddItemToKnown(panda_file::BaseItem *item, const std::map<std::string, panda_file::BaseClassItem *> &cm, 246 const panda_file::FileReader &reader); 247 248 void MergeItem(panda_file::BaseItem *item, const panda_file::FileReader &reader); 249 250 void HandleCandidates(const panda_file::FileReader *reader, const std::vector<panda_file::FieldItem *> &candidates, 251 panda_file::ForeignFieldItem *ff); 252 253 bool MethodFind(const std::string &className, const std::string &methodName, 254 std::map<std::string, panda_file::BaseClassItem *> &classesMap); 255 256 bool FileFind(const std::string &fileName, std::map<std::string, panda_file::BaseClassItem *> &classesMap); 257 258 bool HandleEntryDependencies(); 259 260 class ErrorDetail { 261 public: 262 using InfoType = std::variant<const panda_file::BaseItem *, std::string>; 263 ErrorDetail(std::string name,const panda_file::BaseItem * item1)264 ErrorDetail(std::string name, const panda_file::BaseItem *item1) : name_(std::move(name)), info_(item1) 265 { 266 ASSERT(item1 != nullptr); 267 } 268 name_(std::move (name))269 explicit ErrorDetail(std::string name, std::string data = "") : name_(std::move(name)), info_(std::move(data)) 270 { 271 } 272 GetName()273 const std::string &GetName() const 274 { 275 return name_; 276 } 277 GetInfo()278 const InfoType &GetInfo() const 279 { 280 return info_; 281 } 282 283 private: 284 std::string name_; 285 InfoType info_; 286 }; 287 288 class ErrorToStringWrapper { 289 public: ErrorToStringWrapper(Context * ctx,ErrorDetail error,size_t indent)290 ErrorToStringWrapper(Context *ctx, ErrorDetail error, size_t indent) 291 : error_(std::move(error)), indent_(indent), ctx_(ctx) 292 { 293 } 294 295 DEFAULT_COPY_SEMANTIC(ErrorToStringWrapper); 296 DEFAULT_MOVE_SEMANTIC(ErrorToStringWrapper); 297 298 ~ErrorToStringWrapper() = default; 299 300 friend std::ostream &operator<<(std::ostream &o, const ErrorToStringWrapper &self); 301 302 private: 303 ErrorDetail error_; 304 size_t indent_; 305 Context *ctx_; 306 }; 307 308 ErrorToStringWrapper ErrorToString(ErrorDetail error, size_t indent = 0) 309 { 310 return ErrorToStringWrapper {this, std::move(error), indent}; 311 } 312 313 friend std::ostream &operator<<(std::ostream &o, const ErrorToStringWrapper &self); 314 315 void Error(const std::string &msg, const std::vector<ErrorDetail> &details, 316 const panda_file::FileReader *reader = nullptr); 317 318 std::variant<std::monostate, panda_file::FieldItem *, panda_file::ForeignClassItem *> TryFindField( 319 panda_file::BaseClassItem *klass, const std::string &name, panda_file::TypeItem *expectedType, 320 std::vector<panda_file::FieldItem *> *badCandidates); 321 322 std::variant<bool, panda_file::MethodItem *> TryFindMethod(panda_file::BaseClassItem *klass, 323 panda_file::ForeignMethodItem *fm, 324 std::vector<ErrorDetail> *relatedItems); 325 326 std::variant<panda_file::AnnotationItem *, ErrorDetail> AnnotFromOld(panda_file::AnnotationItem *oa); 327 328 std::variant<panda_file::ValueItem *, ErrorDetail> ArrayValueFromOld(panda_file::ValueItem *oi); 329 330 std::variant<panda_file::ValueItem *, ErrorDetail> ValueFromOld(panda_file::ValueItem *oi); 331 332 std::variant<panda_file::BaseItem *, ErrorDetail> ScalarValueIdFromOld(panda_file::BaseItem *oi); 333 }; 334 335 std::ostream &operator<<(std::ostream &o, const static_linker::Context::ErrorToStringWrapper &self); 336 337 } // namespace ark::static_linker 338 339 #endif 340