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