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