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 #include <tuple>
17 #include <type_traits>
18 #include <variant>
19
20 #include "libpandafile/file_items.h"
21 #include "libpandafile/file_reader.h"
22 #include "libpandafile/proto_data_accessor-inl.h"
23 #include "libpandabase/utils/utf.h"
24
25 #include "linker_context.h"
26
27 namespace {
28 template <typename T>
DerefPtrRef(T && v)29 auto DerefPtrRef(T &&v) -> std::conditional_t<std::is_pointer_v<T>, std::remove_pointer_t<T>, T> &
30 {
31 static_assert(std::is_pointer_v<T> || std::is_reference_v<T>);
32 if constexpr (std::is_pointer_v<T>) {
33 return *v;
34 } else {
35 return v;
36 }
37 }
38 } // namespace
39
40 namespace panda::static_linker {
41
Merge()42 void Context::Merge()
43 {
44 // types can reference types only
45 // methods can reference types
46 // code items can reference everything
47
48 // parse regular classes as forward declarations
49 // parse all foreign classes
50 // parse classes with fields and methods
51 // iterate all known indexed entities and create
52 // appropriate mappings for them
53 // oldEntity -> newEntity
54
55 auto &cm = *cont_.GetClassMap();
56
57 // set offsets of all entities
58 for (auto &reader : readers_) {
59 for (auto [o, i] : *reader.GetItems()) {
60 i->SetOffset(o.GetOffset());
61 }
62 }
63
64 // add regular classes
65 for (auto &reader : readers_) {
66 auto *ic = reader.GetContainerPtr();
67 auto &classes = *ic->GetClassMap();
68
69 knownItems_.reserve(reader.GetItems()->size());
70
71 for (auto [name, i] : classes) {
72 if (i->IsForeign()) {
73 continue;
74 }
75 ASSERT(name == GetStr(i->GetNameItem()));
76
77 if (conf_.partial.count(name) == 0) {
78 if (auto iter = cm.find(name); iter != cm.end()) {
79 Error("Class redefinition", {ErrorDetail("original", iter->second)}, &reader);
80 }
81 }
82 auto clz = cont_.GetOrCreateClassItem(name);
83 knownItems_[i] = clz;
84 cameFrom_.emplace(clz, &reader);
85 }
86 }
87
88 // find all referenced foreign classes
89 for (auto &reader : readers_) {
90 auto *items = reader.GetItems();
91 for (auto &itPair : *items) {
92 auto *item = itPair.second;
93
94 if (item->GetItemType() == panda_file::ItemTypes::FOREIGN_CLASS_ITEM) {
95 auto *fc = static_cast<panda_file::ForeignClassItem *>(item);
96 auto name = GetStr(fc->GetNameItem());
97 if (auto iter = cm.find(name); iter != cm.end()) {
98 knownItems_[fc] = iter->second;
99 } else {
100 auto clz = cont_.GetOrCreateForeignClassItem(name);
101 cameFrom_.emplace(clz, &reader);
102 knownItems_[fc] = clz;
103 }
104 }
105 }
106 }
107
108 // fill regular classes
109 for (auto &reader : readers_) {
110 auto *ic = reader.GetContainerPtr();
111 auto &classes = *ic->GetClassMap();
112
113 for (auto [name, i] : classes) {
114 if (i->IsForeign()) {
115 continue;
116 }
117 ASSERT(cm.find(name) != cm.end());
118 auto ni = static_cast<panda_file::ClassItem *>(cm[name]);
119 auto oi = static_cast<panda_file::ClassItem *>(i);
120 MergeClass(&reader, ni, oi);
121 }
122 }
123
124 // scrap all indexable items
125 for (auto &reader : readers_) {
126 auto *items = reader.GetItems();
127 for (auto [offset, item] : *items) {
128 item->SetOffset(offset.GetOffset());
129
130 switch (item->GetItemType()) {
131 case panda_file::ItemTypes::FOREIGN_METHOD_ITEM:
132 MergeForeignMethod(&reader, static_cast<panda_file::ForeignMethodItem *>(item));
133 break;
134 case panda_file::ItemTypes::FOREIGN_FIELD_ITEM:
135 MergeForeignField(&reader, static_cast<panda_file::ForeignFieldItem *>(item));
136 break;
137 default:;
138 }
139 }
140 }
141
142 for (const auto &f : deferredFailedAnnotations_) {
143 f();
144 }
145 deferredFailedAnnotations_.clear();
146 }
147
MergeClass(const panda_file::FileReader * reader,panda_file::ClassItem * ni,panda_file::ClassItem * oi)148 void Context::MergeClass(const panda_file::FileReader *reader, panda_file::ClassItem *ni, panda_file::ClassItem *oi)
149 {
150 ni->SetAccessFlags(oi->GetAccessFlags());
151 ni->SetPGORank(oi->GetPGORank());
152 ni->SetSourceLang(oi->GetSourceLang());
153 ni->SetSourceFile(StringFromOld(oi->GetSourceFile()));
154
155 ni->SetSuperClass(ClassFromOld(oi->GetSuperClass()));
156
157 for (auto iface : oi->GetInterfaces()) {
158 ni->AddInterface(ClassFromOld(iface));
159 }
160
161 TransferAnnotations(reader, ni, oi);
162
163 oi->VisitFields([this, ni, reader](panda_file::BaseItem *mi) -> bool {
164 ASSERT(mi->GetItemType() == panda_file::ItemTypes::FIELD_ITEM);
165 MergeField(reader, ni, reinterpret_cast<panda_file::FieldItem *>(mi));
166 return true;
167 });
168
169 oi->VisitMethods([this, ni, reader](panda_file::BaseItem *mi) -> bool {
170 ASSERT(mi->GetItemType() == panda_file::ItemTypes::METHOD_ITEM);
171 MergeMethod(reader, ni, reinterpret_cast<panda_file::MethodItem *>(mi));
172 return true;
173 });
174 }
175
MergeField(const panda_file::FileReader * reader,panda_file::ClassItem * clz,panda_file::FieldItem * oi)176 void Context::MergeField(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::FieldItem *oi)
177 {
178 auto ni = clz->AddField(StringFromOld(oi->GetNameItem()), TypeFromOld(oi->GetTypeItem()), oi->GetAccessFlags());
179 knownItems_[oi] = ni;
180 cameFrom_.emplace(ni, reader);
181
182 TransferAnnotations(reader, ni, oi);
183 }
184
MergeMethod(const panda_file::FileReader * reader,panda_file::ClassItem * clz,panda_file::MethodItem * oi)185 void Context::MergeMethod(const panda_file::FileReader *reader, panda_file::ClassItem *clz, panda_file::MethodItem *oi)
186 {
187 auto [proto, params] = GetProto(oi->GetProto());
188 auto &oldParams = oi->GetParams();
189 auto *ni = clz->AddMethod(StringFromOld(oi->GetNameItem()), proto, oi->GetAccessFlags(), params);
190 knownItems_[oi] = ni;
191 cameFrom_.emplace(ni, reader);
192 ni->SetProfileSize(oi->GetProfileSize());
193
194 for (size_t i = 0; i < oldParams.size(); i++) {
195 TransferAnnotations(reader, &ni->GetParams()[i], &oldParams[i]);
196 }
197
198 TransferAnnotations(reader, ni, oi);
199
200 if (ni->HasRuntimeParamAnnotations()) {
201 cont_.CreateItem<panda_file::ParamAnnotationsItem>(ni, true);
202 }
203
204 if (ni->HasParamAnnotations()) {
205 cont_.CreateItem<panda_file::ParamAnnotationsItem>(ni, false);
206 }
207
208 auto shouldSave = false;
209 std::vector<uint8_t> *instructions = nullptr;
210
211 auto patchLnp = false;
212
213 if (auto odbg = oi->GetDebugInfo(); !conf_.stripDebugInfo && odbg != nullptr) {
214 panda_file::LineNumberProgramItem *lnpItem {};
215
216 auto oldProgram = odbg->GetLineNumberProgram();
217 if (auto old = knownItems_.find(oldProgram); old != knownItems_.end()) {
218 lnpItem = static_cast<panda_file::LineNumberProgramItem *>(old->second);
219 cont_.IncRefLineNumberProgramItem(lnpItem);
220 } else {
221 lnpItem = cont_.CreateLineNumberProgramItem();
222 knownItems_.emplace(oldProgram, lnpItem);
223
224 shouldSave = true;
225 result_.stats.debugCount++;
226 patchLnp = true;
227 }
228
229 auto *ndbg = cont_.CreateItem<panda_file::DebugInfoItem>(lnpItem);
230 ndbg->SetLineNumber(odbg->GetLineNumber());
231 ni->SetDebugInfo(ndbg);
232 for (auto *s : *odbg->GetParameters()) {
233 ndbg->AddParameter(StringFromOld(s));
234 }
235 }
236
237 if (auto oci = oi->GetCode(); oci != nullptr) {
238 shouldSave = true;
239 result_.stats.codeCount++;
240
241 auto nci = cont_.CreateItem<panda_file::CodeItem>();
242 ni->SetCode(nci);
243 nci->SetPGORank(oci->GetPGORank());
244 nci->SetNumArgs(oci->GetNumArgs());
245 nci->SetNumVregs(oci->GetNumVregs());
246 *nci->GetInstructions() = *oci->GetInstructions();
247 instructions = nci->GetInstructions();
248 nci->SetNumInstructions(oci->GetNumInstructions());
249
250 for (const auto &otb : oci->GetTryBlocks()) {
251 auto ncbs = std::vector<panda_file::CodeItem::CatchBlock>();
252 const auto &ocbs = otb.GetCatchBlocks();
253 ncbs.reserve(ocbs.size());
254 for (const auto &ocb : ocbs) {
255 ASSERT(ocb.GetMethod() == oi);
256 auto excKlass = ClassFromOld(ocb.GetType());
257 if (excKlass != nullptr) {
258 ni->AddIndexDependency(excKlass);
259 }
260 ncbs.emplace_back(ni, excKlass, ocb.GetHandlerPc(), ocb.GetCodeSize());
261 }
262 auto ntb = panda_file::CodeItem::TryBlock(otb.GetStartPc(), otb.GetLength(), ncbs);
263 nci->AddTryBlock(ntb);
264 }
265 }
266
267 if (shouldSave) {
268 codeDatas_.push_back(CodeData {instructions, oi, ni, reader, patchLnp});
269 }
270 }
271
IsSameType(panda::panda_file::TypeItem * nevv,panda::panda_file::TypeItem * old)272 bool Context::IsSameType(panda::panda_file::TypeItem *nevv, panda::panda_file::TypeItem *old)
273 {
274 if (nevv->GetType().IsPrimitive()) {
275 if (!old->GetType().IsPrimitive()) {
276 return false;
277 }
278 return nevv->GetType() == old->GetType();
279 }
280
281 auto iter = knownItems_.find(old);
282 return iter != knownItems_.end() && iter->second == nevv;
283 }
284
TryFindMethod(panda_file::BaseClassItem * klass,panda_file::ForeignMethodItem * fm,std::vector<ErrorDetail> * relatedItems)285 std::variant<bool, panda_file::MethodItem *> Context::TryFindMethod(panda_file::BaseClassItem *klass,
286 panda_file::ForeignMethodItem *fm,
287 std::vector<ErrorDetail> *relatedItems)
288 {
289 if (klass == nullptr) {
290 return false;
291 }
292 if (klass->GetItemType() == panda_file::ItemTypes::FOREIGN_CLASS_ITEM) {
293 return true;
294 }
295 ASSERT(klass->GetItemType() == panda_file::ItemTypes::CLASS_ITEM);
296 auto kls = static_cast<panda_file::ClassItem *>(klass);
297 auto op = fm->GetProto();
298
299 auto [new_meth_beg, new_meth_end] = kls->FindMethod(fm->GetNameItem());
300
301 for (auto beg = new_meth_beg; beg != new_meth_end; ++beg) {
302 auto nm = beg->get();
303 auto np = nm->GetProto();
304
305 relatedItems->emplace_back("candidate", nm);
306
307 if (op->GetRefTypes().size() != np->GetRefTypes().size()) {
308 continue;
309 }
310
311 if (op->GetShorty() != np->GetShorty()) {
312 continue;
313 }
314
315 bool ok = true;
316 for (size_t i = 0; i < op->GetRefTypes().size(); i++) {
317 if (!IsSameType(np->GetRefTypes()[i], op->GetRefTypes()[i])) {
318 ok = false;
319 break;
320 }
321 }
322
323 if (ok) {
324 return nm;
325 }
326 }
327
328 panda_file::BaseClassItem *searchIn = kls->GetSuperClass();
329 size_t idx = 0;
330 while (true) {
331 auto res = TryFindMethod(searchIn, fm, relatedItems);
332 if (std::holds_alternative<bool>(res)) {
333 if (std::get<bool>(res)) {
334 return res;
335 }
336 }
337 if (std::holds_alternative<panda_file::MethodItem *>(res)) {
338 return res;
339 }
340 if (idx >= kls->GetInterfaces().size()) {
341 return false;
342 }
343 searchIn = kls->GetInterfaces()[idx++];
344 }
345 return false;
346 }
347
MergeForeignMethod(const panda_file::FileReader * reader,panda_file::ForeignMethodItem * fm)348 void Context::MergeForeignMethod(const panda_file::FileReader *reader, panda_file::ForeignMethodItem *fm)
349 {
350 ASSERT(knownItems_.find(fm) == knownItems_.end());
351 ASSERT(knownItems_.find(fm->GetClassItem()) != knownItems_.end());
352 auto clz = static_cast<panda_file::BaseClassItem *>(knownItems_[fm->GetClassItem()]);
353 std::vector<panda::static_linker::Context::ErrorDetail> details = {{"method", fm}};
354 auto res = TryFindMethod(clz, fm, &details);
355 if (std::holds_alternative<bool>(res) || conf_.remainsPartial.count(GetStr(clz->GetNameItem())) != 0) {
356 if (std::get<bool>(res) || conf_.remainsPartial.count(GetStr(clz->GetNameItem())) != 0) {
357 MergeForeignMethodCreate(reader, clz, fm);
358 } else {
359 Error("Unresolved method", details, reader);
360 }
361 } else {
362 ASSERT(std::holds_alternative<panda_file::MethodItem *>(res));
363 auto meth = std::get<panda_file::MethodItem *>(res);
364 if (meth->GetClassItem() != ClassFromOld(fm->GetClassItem())) {
365 LOG(DEBUG, STATIC_LINKER) << "Resolved method\n"
366 << ErrorToString({"old method", fm}, 1) << '\n'
367 << ErrorToString({"new method", meth}, 1);
368 }
369 knownItems_[fm] = meth;
370 }
371 }
372
MergeForeignMethodCreate(const panda_file::FileReader * reader,panda_file::BaseClassItem * clz,panda_file::ForeignMethodItem * fm)373 void Context::MergeForeignMethodCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz,
374 panda_file::ForeignMethodItem *fm)
375 {
376 auto *fc = static_cast<panda_file::BaseClassItem *>(clz);
377 auto name = StringFromOld(fm->GetNameItem());
378 auto proto = GetProto(fm->GetProto()).first;
379 auto access = fm->GetAccessFlags();
380 auto [iter, was_inserted] = foreignMethods_.emplace(
381 std::piecewise_construct, std::forward_as_tuple(fc, name, proto, access), std::forward_as_tuple(nullptr));
382 if (was_inserted) {
383 iter->second = cont_.CreateItem<panda_file::ForeignMethodItem>(fc, name, proto, access);
384 } else {
385 result_.stats.deduplicatedForeigners++;
386 }
387 auto nfm = iter->second;
388 cameFrom_.emplace(nfm, reader);
389 knownItems_[fm] = nfm;
390 }
391
TryFindField(panda_file::BaseClassItem * klass,const std::string & name,panda_file::TypeItem * expectedType,std::vector<panda_file::FieldItem * > * badCandidates)392 std::variant<std::monostate, panda_file::FieldItem *, panda_file::ForeignClassItem *> Context::TryFindField(
393 panda_file::BaseClassItem *klass, const std::string &name, panda_file::TypeItem *expectedType,
394 std::vector<panda_file::FieldItem *> *badCandidates)
395 {
396 if (klass == nullptr) {
397 return std::monostate {};
398 }
399 if (klass->GetItemType() == panda_file::ItemTypes::FOREIGN_CLASS_ITEM) {
400 return static_cast<panda_file::ForeignClassItem *>(klass);
401 }
402 auto kls = static_cast<panda_file::ClassItem *>(klass);
403 panda_file::FieldItem *newFld = nullptr;
404 kls->VisitFields([&](panda_file::BaseItem *bi) {
405 ASSERT(bi->GetItemType() == panda_file::ItemTypes::FIELD_ITEM);
406 auto fld = static_cast<panda_file::FieldItem *>(bi);
407 if (fld->GetNameItem()->GetData() != name) {
408 return true;
409 }
410 if (fld->GetTypeItem() != expectedType) {
411 if (badCandidates != nullptr) {
412 badCandidates->push_back(fld);
413 }
414 return true;
415 }
416 newFld = fld;
417 return false;
418 });
419 if (newFld != nullptr) {
420 return newFld;
421 }
422 return TryFindField(kls->GetSuperClass(), name, expectedType, badCandidates);
423 }
424
MergeForeignField(const panda_file::FileReader * reader,panda_file::ForeignFieldItem * ff)425 void Context::MergeForeignField(const panda_file::FileReader *reader, panda_file::ForeignFieldItem *ff)
426 {
427 ASSERT(knownItems_.find(ff) == knownItems_.end());
428 ASSERT(knownItems_.find(ff->GetClassItem()) != knownItems_.end());
429 auto clz = static_cast<panda_file::BaseClassItem *>(knownItems_[ff->GetClassItem()]);
430 if (clz->GetItemType() != panda_file::ItemTypes::FOREIGN_CLASS_ITEM) {
431 ASSERT(clz->GetItemType() == panda_file::ItemTypes::CLASS_ITEM);
432 auto rclz = static_cast<panda_file::ClassItem *>(clz);
433 std::vector<panda_file::FieldItem *> candidates;
434 auto res = TryFindField(rclz, ff->GetNameItem()->GetData(), TypeFromOld(ff->GetTypeItem()), &candidates);
435
436 std::visit(
437 [&](auto el) {
438 using T = decltype(el);
439 if constexpr (std::is_same_v<T, std::monostate>) {
440 if (conf_.remainsPartial.count(GetStr(clz->GetNameItem())) != 0) {
441 MergeForeignFieldCreate(reader, clz, ff);
442 } else {
443 auto details = std::vector<ErrorDetail> {{"field", ff}};
444 for (const auto &c : candidates) {
445 details.emplace_back("candidate", c);
446 }
447 Error("Unresolved field", details, reader);
448 }
449 } else if constexpr (std::is_same_v<T, panda_file::FieldItem *>) {
450 knownItems_[ff] = el;
451 } else {
452 ASSERT((std::is_same_v<T, panda_file::ForeignClassItem *>));
453 // el or klass? propagate field to base or not?
454 auto fieldKlass = el;
455 LOG(DEBUG, STATIC_LINKER) << "Propagating foreign field to base\n"
456 << ErrorToString({"field", ff}, 1) << '\n'
457 << ErrorToString({"new base", fieldKlass}, 1);
458 MergeForeignFieldCreate(reader, fieldKlass, ff);
459 }
460 },
461 res);
462 } else {
463 MergeForeignFieldCreate(reader, clz, ff);
464 }
465 }
466
MergeForeignFieldCreate(const panda_file::FileReader * reader,panda_file::BaseClassItem * clz,panda_file::ForeignFieldItem * ff)467 void Context::MergeForeignFieldCreate(const panda_file::FileReader *reader, panda_file::BaseClassItem *clz,
468 panda_file::ForeignFieldItem *ff)
469 {
470 auto *fc = static_cast<panda_file::ForeignClassItem *>(clz);
471 auto name = StringFromOld(ff->GetNameItem());
472 auto typ = TypeFromOld(ff->GetTypeItem());
473 auto [iter, was_inserted] = foreignFields_.emplace(std::piecewise_construct, std::forward_as_tuple(fc, name, typ),
474 std::forward_as_tuple(nullptr));
475 if (was_inserted) {
476 iter->second = cont_.CreateItem<panda_file::ForeignFieldItem>(fc, name, typ);
477 } else {
478 result_.stats.deduplicatedForeigners++;
479 }
480
481 auto nff = iter->second;
482 cameFrom_.emplace(nff, reader);
483 knownItems_[ff] = nff;
484 }
485
BreakProto(panda_file::ProtoItem * p)486 std::vector<panda_file::Type> Helpers::BreakProto(panda_file::ProtoItem *p)
487 {
488 auto &shorty = p->GetShorty();
489
490 auto ret = std::vector<panda_file::Type>();
491 ret.reserve(panda_file::SHORTY_ELEM_PER16 * shorty.size());
492
493 // SHORTY
494 size_t numElem = 0;
495 size_t numRefs = 0;
496 auto fetch = [idx = size_t(0), &shorty]() mutable {
497 ASSERT(idx < shorty.size());
498 return shorty[idx++];
499 };
500
501 auto v = fetch();
502
503 while (v != 0) {
504 auto shift = (numElem % panda_file::SHORTY_ELEM_PER16) * panda_file::SHORTY_ELEM_WIDTH;
505
506 auto elem = (static_cast<decltype(shift)>(v) >> shift) & panda_file::SHORTY_ELEM_MASK;
507
508 if (elem == 0) {
509 break;
510 }
511 auto asId = panda_file::Type::TypeId(elem);
512 ASSERT(asId != panda_file::Type::TypeId::INVALID);
513
514 auto t = panda_file::Type(asId);
515 if (t.IsReference()) {
516 numRefs++;
517 }
518 static_assert(std::is_trivially_copyable_v<decltype(t)>);
519 ret.emplace_back(t);
520
521 numElem++;
522
523 if (numElem % panda_file::SHORTY_ELEM_PER16 == 0) {
524 v = fetch();
525 }
526 }
527
528 ASSERT(numRefs == p->GetRefTypes().size());
529 ASSERT(!ret.empty());
530
531 return ret;
532 }
533
GetProto(panda_file::ProtoItem * p)534 std::pair<panda_file::ProtoItem *, std::vector<panda_file::MethodParamItem>> Context::GetProto(panda_file::ProtoItem *p)
535 {
536 auto &refs = p->GetRefTypes();
537
538 auto typs = Helpers::BreakProto(p);
539
540 panda_file::TypeItem *ret = nullptr;
541 auto params = std::vector<panda_file::MethodParamItem>();
542 params.reserve(typs.size() - 1);
543
544 size_t numRefs = 0;
545
546 for (auto const &t : typs) {
547 panda_file::TypeItem *ti;
548
549 if (t.IsReference()) {
550 ASSERT(numRefs < refs.size());
551 ti = TypeFromOld(refs[numRefs++]);
552 } else {
553 ti = cont_.GetOrCreatePrimitiveTypeItem(t);
554 }
555
556 if (ret == nullptr) {
557 ret = ti;
558 } else {
559 params.emplace_back(ti);
560 }
561 }
562
563 ASSERT(numRefs == refs.size());
564 ASSERT(ret != nullptr);
565
566 auto proto = cont_.GetOrCreateProtoItem(ret, params);
567
568 return std::make_pair(proto, std::move(params));
569 }
570
571 template <typename T, typename Getter, typename Adder>
AddAnnotationImpl(AddAnnotationImplData<T> ad,Getter getter,Adder adder)572 void Context::AddAnnotationImpl(AddAnnotationImplData<T> ad, Getter getter, Adder adder)
573 {
574 const auto &oldAnnotList = DerefPtrRef(getter(ad.oi));
575 for (size_t ind = ad.from; ind < oldAnnotList.size(); ind++) {
576 auto oldAnnot = oldAnnotList[ind];
577 auto mbNewAnnot = AnnotFromOld(oldAnnot);
578 if (std::holds_alternative<panda_file::AnnotationItem *>(mbNewAnnot)) {
579 adder(ad.ni, std::get<panda_file::AnnotationItem *>(mbNewAnnot));
580 return;
581 }
582 const auto &ed = std::get<ErrorDetail>(mbNewAnnot);
583 if (ad.retriesLeft-- == 0) {
584 std::vector<ErrorDetail> details {ErrorDetail {"annotation", oldAnnot}, ed};
585 if constexpr (std::is_base_of_v<panda_file::BaseItem, std::decay_t<T>>) {
586 details.emplace_back("old item", ad.oi);
587 details.emplace_back("new item", ad.ni);
588 }
589 this->Error("can't transfer annotation", details, ad.reader);
590 return;
591 }
592
593 LOG(DEBUG, STATIC_LINKER) << "defer annotation transferring due to" << ErrorToString(ed, 1);
594 ad.from = ind;
595 deferredFailedAnnotations_.emplace_back([=]() { AddAnnotationImpl<T>(ad, getter, adder); });
596 return;
597 }
598 }
599
600 template <typename T>
TransferAnnotations(const panda_file::FileReader * reader,T * ni,T * oi)601 void Context::TransferAnnotations(const panda_file::FileReader *reader, T *ni, T *oi)
602 {
603 AddAnnotationImplData<T> data {reader, ni, oi, 0, 1};
604 // pointers to members break clang-12 on CI
605 AddAnnotationImpl(
606 data, [](T *self) -> decltype(auto) { return DerefPtrRef(self->GetRuntimeAnnotations()); },
607 [](T *self, panda_file::AnnotationItem *an) { self->AddRuntimeAnnotation(an); });
608 AddAnnotationImpl(
609 data, [](T *self) -> decltype(auto) { return DerefPtrRef(self->GetAnnotations()); },
610 [](T *self, panda_file::AnnotationItem *an) { self->AddAnnotation(an); });
611 AddAnnotationImpl(
612 data, [](T *self) -> decltype(auto) { return DerefPtrRef(self->GetRuntimeTypeAnnotations()); },
613 [](T *self, panda_file::AnnotationItem *an) { self->AddRuntimeTypeAnnotation(an); });
614 AddAnnotationImpl(
615 data, [](T *self) -> decltype(auto) { return DerefPtrRef(self->GetTypeAnnotations()); },
616 [](T *self, panda_file::AnnotationItem *an) { self->AddTypeAnnotation(an); });
617 }
618
AnnotFromOld(panda_file::AnnotationItem * oa)619 std::variant<panda_file::AnnotationItem *, Context::ErrorDetail> Context::AnnotFromOld(panda_file::AnnotationItem *oa)
620 {
621 if (auto iter = knownItems_.find(oa); iter != knownItems_.end()) {
622 return static_cast<panda_file::AnnotationItem *>(iter->second);
623 }
624
625 using Elem = panda_file::AnnotationItem::Elem;
626
627 const auto &oldElems = *oa->GetElements();
628 auto newElems = std::vector<Elem>();
629 newElems.reserve(oldElems.size());
630 for (const auto &oe : oldElems) {
631 auto name = StringFromOld(oe.GetName());
632 auto *oldVal = oe.GetValue();
633 panda_file::ValueItem *newVal {};
634
635 using ValueType = panda_file::ValueItem::Type;
636 switch (oldVal->GetType()) {
637 case ValueType::INTEGER:
638 newVal = cont_.GetOrCreateIntegerValueItem(oldVal->GetAsScalar()->GetValue<uint32_t>());
639 break;
640 case ValueType::LONG:
641 newVal = cont_.GetOrCreateLongValueItem(oldVal->GetAsScalar()->GetValue<uint64_t>());
642 break;
643 case ValueType::FLOAT:
644 newVal = cont_.GetOrCreateFloatValueItem(oldVal->GetAsScalar()->GetValue<float>());
645 break;
646 case ValueType::DOUBLE:
647 newVal = cont_.GetOrCreateDoubleValueItem(oldVal->GetAsScalar()->GetValue<double>());
648 break;
649 case ValueType::ID: {
650 auto oldItem = oldVal->GetAsScalar()->GetIdItem();
651 ASSERT(oldItem != nullptr);
652 auto newItem = ScalarValueIdFromOld(oldItem);
653 if (std::holds_alternative<ErrorDetail>(newItem)) {
654 return std::move(std::get<ErrorDetail>(newItem));
655 }
656 newVal = cont_.GetOrCreateIdValueItem(std::get<panda_file::BaseItem *>(newItem));
657 break;
658 }
659 case ValueType::ARRAY: {
660 auto old = oldVal->GetAsArray();
661 auto its = old->GetItems();
662 for (auto &i : its) {
663 if (i.HasValue<panda_file::BaseItem *>()) {
664 auto vl = ScalarValueIdFromOld(i.GetIdItem());
665 if (std::holds_alternative<ErrorDetail>(vl)) {
666 return std::move(std::get<ErrorDetail>(vl));
667 }
668 i = panda_file::ScalarValueItem(std::get<panda_file::BaseItem *>(vl));
669 }
670 }
671 newVal = cont_.CreateItem<panda_file::ArrayValueItem>(old->GetComponentType(), std::move(its));
672 break;
673 }
674 default:
675 UNREACHABLE();
676 }
677
678 ASSERT(newVal != nullptr);
679 newElems.emplace_back(name, newVal);
680 }
681
682 auto clzIt = knownItems_.find(oa->GetClassItem());
683 ASSERT(clzIt != knownItems_.end());
684 ASSERT(clzIt->second->GetItemType() == panda_file::ItemTypes::CLASS_ITEM ||
685 clzIt->second->GetItemType() == panda_file::ItemTypes::FOREIGN_CLASS_ITEM);
686 auto clz = static_cast<panda_file::BaseClassItem *>(clzIt->second);
687
688 auto na = cont_.CreateItem<panda_file::AnnotationItem>(clz, std::move(newElems), oa->GetTags());
689 knownItems_.emplace(oa, na);
690 return na;
691 }
692
ScalarValueIdFromOld(panda_file::BaseItem * oi)693 std::variant<panda_file::BaseItem *, Context::ErrorDetail> Context::ScalarValueIdFromOld(panda_file::BaseItem *oi)
694 {
695 if (auto newItemIt = knownItems_.find(static_cast<panda_file::IndexedItem *>(oi)); newItemIt != knownItems_.end()) {
696 return newItemIt->second;
697 }
698 if (oi->GetItemType() == panda_file::ItemTypes::STRING_ITEM) {
699 return StringFromOld(static_cast<panda_file::StringItem *>(oi));
700 }
701 if (oi->GetItemType() == panda_file::ItemTypes::ANNOTATION_ITEM) {
702 auto oa = static_cast<panda_file::AnnotationItem *>(oi);
703 using ReturnType = decltype(ScalarValueIdFromOld(oi));
704 return std::visit([](auto &&a) -> ReturnType { return std::forward<decltype(a)>(a); }, AnnotFromOld(oa));
705 }
706 return ErrorDetail("id", oi);
707 }
708
Parse()709 void Context::Parse()
710 {
711 for (auto &codeData : codeDatas_) {
712 ProcessCodeData(patcher_, &codeData);
713 }
714 patcher_.ApplyDeps(this);
715 }
716
ComputeLayout()717 void Context::ComputeLayout()
718 {
719 cont_.ComputeLayout();
720 }
721
Patch()722 void Context::Patch()
723 {
724 patcher_.Patch({0, patcher_.GetSize()});
725 }
726
ClassFromOld(panda_file::BaseClassItem * old)727 panda_file::BaseClassItem *Context::ClassFromOld(panda_file::BaseClassItem *old)
728 {
729 if (old == nullptr) {
730 return old;
731 }
732 auto &cm = *cont_.GetClassMap();
733 if (auto iter = cm.find(GetStr(old->GetNameItem())); iter != cm.end()) {
734 return iter->second;
735 }
736 UNREACHABLE();
737 }
738
TypeFromOld(panda_file::TypeItem * old)739 panda_file::TypeItem *Context::TypeFromOld(panda_file::TypeItem *old)
740 {
741 const auto ty = old->GetType();
742 if (ty.IsPrimitive()) {
743 return cont_.GetOrCreatePrimitiveTypeItem(ty.GetId());
744 }
745 ASSERT(old->GetItemType() == panda_file::ItemTypes::CLASS_ITEM ||
746 old->GetItemType() == panda_file::ItemTypes::FOREIGN_CLASS_ITEM);
747 return ClassFromOld(static_cast<panda_file::BaseClassItem *>(old));
748 }
749
GetStr(const panda_file::StringItem * si)750 std::string Context::GetStr(const panda_file::StringItem *si)
751 {
752 return utf::Mutf8AsCString(reinterpret_cast<const uint8_t *>(si->GetData().data()));
753 }
754
StringFromOld(const panda_file::StringItem * s)755 panda_file::StringItem *Context::StringFromOld(const panda_file::StringItem *s)
756 {
757 if (s == nullptr) {
758 return nullptr;
759 }
760 return cont_.GetOrCreateStringItem(GetStr(s));
761 }
762 } // namespace panda::static_linker
763