1 /** 2 * Copyright (c) 2021-2022 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 panda::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(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 MergeMethod(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::MethodItem *oi); 185 186 void MergeField(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::FieldItem *oi); 187 188 void MergeForeignMethod(const panda_file::FileReader *reader, panda_file::ForeignMethodItem *fm); 189 190 void MergeForeignMethodCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz, 191 panda_file::ForeignMethodItem *fm); 192 193 void MergeForeignField(const panda_file::FileReader *reader, panda_file::ForeignFieldItem *ff); 194 195 void MergeForeignFieldCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz, 196 panda_file::ForeignFieldItem *ff); 197 198 template <typename T> 199 struct AddAnnotationImplData { 200 const panda_file::FileReader *reader; 201 T *ni; 202 T *oi; 203 size_t from; 204 size_t retriesLeft; 205 }; 206 207 template <typename T, typename Getter, typename Adder> 208 void AddAnnotationImpl(AddAnnotationImplData<T> ad, Getter getter, Adder adder); 209 210 template <typename T> 211 void TransferAnnotations(const panda_file::FileReader *reader, T *ni, T *oi); 212 213 std::pair<panda_file::ProtoItem *, std::vector<panda_file::MethodParamItem>> GetProto(panda_file::ProtoItem *p); 214 215 bool IsSameType(panda::panda_file::TypeItem *nevv, panda::panda_file::TypeItem *old); 216 217 void ProcessCodeData(CodePatcher &p, CodeData *data); 218 219 class ErrorDetail { 220 public: 221 using InfoType = std::variant<const panda_file::BaseItem *, std::string>; 222 ErrorDetail(std::string name,const panda_file::BaseItem * item1)223 ErrorDetail(std::string name, const panda_file::BaseItem *item1) : name_(std::move(name)), info_(item1) 224 { 225 ASSERT(item1 != nullptr); 226 } 227 name_(std::move (name))228 explicit ErrorDetail(std::string name, std::string data = "") : name_(std::move(name)), info_(std::move(data)) 229 { 230 } 231 GetName()232 const std::string &GetName() const 233 { 234 return name_; 235 } 236 GetInfo()237 const InfoType &GetInfo() const 238 { 239 return info_; 240 } 241 242 private: 243 std::string name_; 244 InfoType info_; 245 }; 246 247 class ErrorToStringWrapper { 248 public: ErrorToStringWrapper(Context * ctx,ErrorDetail error,size_t indent)249 ErrorToStringWrapper(Context *ctx, ErrorDetail error, size_t indent) 250 : error_(std::move(error)), indent_(indent), ctx_(ctx) 251 { 252 } 253 254 DEFAULT_COPY_SEMANTIC(ErrorToStringWrapper); 255 DEFAULT_MOVE_SEMANTIC(ErrorToStringWrapper); 256 257 ~ErrorToStringWrapper() = default; 258 259 friend std::ostream &operator<<(std::ostream &o, const ErrorToStringWrapper &self); 260 261 private: 262 ErrorDetail error_; 263 size_t indent_; 264 Context *ctx_; 265 }; 266 267 ErrorToStringWrapper ErrorToString(ErrorDetail error, size_t indent = 0) 268 { 269 return ErrorToStringWrapper {this, std::move(error), indent}; 270 } 271 272 friend std::ostream &operator<<(std::ostream &o, const ErrorToStringWrapper &self); 273 274 void Error(const std::string &msg, const std::vector<ErrorDetail> &details, 275 const panda_file::FileReader *reader = nullptr); 276 277 std::variant<std::monostate, panda_file::FieldItem *, panda_file::ForeignClassItem *> TryFindField( 278 panda_file::BaseClassItem *klass, const std::string &name, panda_file::TypeItem *expectedType, 279 std::vector<panda_file::FieldItem *> *badCandidates); 280 281 std::variant<bool, panda_file::MethodItem *> TryFindMethod(panda_file::BaseClassItem *klass, 282 panda_file::ForeignMethodItem *fm, 283 std::vector<ErrorDetail> *relatedItems); 284 285 std::variant<panda_file::AnnotationItem *, ErrorDetail> AnnotFromOld(panda_file::AnnotationItem *oa); 286 287 std::variant<panda_file::BaseItem *, ErrorDetail> ScalarValueIdFromOld(panda_file::BaseItem *oi); 288 }; 289 290 std::ostream &operator<<(std::ostream &o, const static_linker::Context::ErrorToStringWrapper &self); 291 292 } // namespace panda::static_linker 293 294 #endif 295