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