• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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