Skip to content

Commit edc7109

Browse files
Merge pull request #82244 from adrian-prantl/expected-lowering
[Reflection] Add lightweight error handling to ReflectionContext
2 parents 3269c06 + 868c991 commit edc7109

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

include/swift/RemoteInspection/ReflectionContext.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/BinaryFormat/MachO.h"
2323
#include "llvm/BinaryFormat/ELF.h"
2424
#include "llvm/Object/COFF.h"
25+
#include "llvm/Support/Error.h"
2526
#include "llvm/Support/Memory.h"
2627
#include "llvm/ADT/STLExtras.h"
2728

@@ -1276,6 +1277,15 @@ class ReflectionContext
12761277
}
12771278
}
12781279

1280+
llvm::Expected<const TypeInfo &>
1281+
getTypeInfo(const TypeRef &TR, remote::TypeInfoProvider *ExternalTypeInfo) {
1282+
auto &TC = getBuilder().getTypeConverter();
1283+
const TypeInfo *TI = TC.getTypeInfo(&TR, ExternalTypeInfo);
1284+
if (!TI)
1285+
return llvm::createStringError(TC.takeLastError());
1286+
return *TI;
1287+
}
1288+
12791289
/// Given a typeref, attempt to calculate the unaligned start of this
12801290
/// instance's fields. For example, for a type without a superclass, the start
12811291
/// of the instance fields would after the word for the isa pointer and the

include/swift/RemoteInspection/TypeLowering.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,8 @@ class ArrayTypeInfo : public TypeInfo {
373373
class TypeConverter {
374374
TypeRefBuilder &Builder;
375375
std::vector<std::unique_ptr<const TypeInfo>> Pool;
376-
llvm::DenseMap<std::pair<const TypeRef *, remote::TypeInfoProvider::IdType>,
377-
const TypeInfo *> Cache;
376+
using KeyT = std::pair<const TypeRef *, remote::TypeInfoProvider::IdType>;
377+
llvm::DenseMap<KeyT, const TypeInfo *> Cache;
378378
llvm::DenseSet<const TypeRef *> RecursionCheck;
379379
llvm::DenseMap<std::pair<unsigned, unsigned>,
380380
const ReferenceTypeInfo *> ReferenceCache;
@@ -391,9 +391,25 @@ class TypeConverter {
391391
const TypeInfo *DefaultActorStorageTI = nullptr;
392392
const TypeInfo *EmptyTI = nullptr;
393393

394+
/// Used for lightweight error handling. We don't have access to
395+
/// llvm::Expected<> here, so TypeConverter just stores a pointer to the last
396+
/// encountered error instead that is stored in the cache.
397+
using TCError = std::pair<const char *, const TypeRef *>;
398+
TCError LastError = {nullptr, nullptr};
399+
std::unique_ptr<llvm::DenseMap<KeyT, TCError>> ErrorCache;
400+
394401
public:
395402
explicit TypeConverter(TypeRefBuilder &Builder) : Builder(Builder) {}
396403

404+
/// Called by LLDB.
405+
void enableErrorCache() {
406+
ErrorCache = std::make_unique<llvm::DenseMap<KeyT, TCError>>();
407+
}
408+
void setError(const char *msg, const TypeRef *TR) { LastError = {msg, TR}; }
409+
410+
/// Retreive the error and reset it.
411+
std::string takeLastError();
412+
397413
TypeRefBuilder &getBuilder() { return Builder; }
398414

399415
/// Tests if the type is concrete enough that its size is known.
@@ -474,8 +490,10 @@ class RecordTypeInfoBuilder {
474490
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
475491
BitwiseTakable(true), Kind(Kind), Empty(true), Invalid(false) {}
476492

477-
bool isInvalid() const {
478-
return Invalid;
493+
bool isInvalid() const { return Invalid; }
494+
void markInvalid(const char *msg, const TypeRef *TR = nullptr) {
495+
Invalid = true;
496+
TC.setError(msg, TR);
479497
}
480498

481499
unsigned addField(unsigned fieldSize, unsigned fieldAlignment,

stdlib/public/RemoteInspection/TypeLowering.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,12 @@ class ExistentialTypeInfoBuilder {
11601160
unsigned WitnessTableCount;
11611161
bool Invalid;
11621162

1163+
void markInvalid(const char *msg, const TypeRef *TR = nullptr) {
1164+
Invalid = true;
1165+
DEBUG_LOG(fprintf(stderr, "%s\n", msg); if (TR) TR->dump());
1166+
TC.setError(msg, TR);
1167+
}
1168+
11631169
bool isSingleError() const {
11641170
// If we changed representation, it means we added a
11651171
// superclass constraint or an AnyObject member.
@@ -1191,8 +1197,7 @@ class ExistentialTypeInfoBuilder {
11911197
auto *NTD = dyn_cast<NominalTypeRef>(P);
11921198
auto *OP = dyn_cast<ObjCProtocolTypeRef>(P);
11931199
if (!NTD && !OP) {
1194-
DEBUG_LOG(fprintf(stderr, "Bad protocol: "); P->dump())
1195-
Invalid = true;
1200+
markInvalid("bad protocol", P);
11961201
continue;
11971202
}
11981203

@@ -1204,8 +1209,7 @@ class ExistentialTypeInfoBuilder {
12041209

12051210
auto FD = TC.getBuilder().getFieldDescriptor(P);
12061211
if (FD == nullptr) {
1207-
DEBUG_LOG(fprintf(stderr, "No field descriptor: "); P->dump())
1208-
Invalid = true;
1212+
markInvalid("no field descriptor", P);
12091213
continue;
12101214
}
12111215

@@ -1224,16 +1228,12 @@ class ExistentialTypeInfoBuilder {
12241228
// layering.
12251229
auto *SuperclassTI = TC.getTypeInfo(Superclass, nullptr);
12261230
if (SuperclassTI == nullptr) {
1227-
DEBUG_LOG(fprintf(stderr, "No TypeInfo for superclass: ");
1228-
Superclass->dump());
1229-
Invalid = true;
1231+
markInvalid("no type info for superclass", Superclass);
12301232
continue;
12311233
}
12321234

12331235
if (!isa<ReferenceTypeInfo>(SuperclassTI)) {
1234-
DEBUG_LOG(fprintf(stderr, "Superclass not a reference type: ");
1235-
SuperclassTI->dump());
1236-
Invalid = true;
1236+
markInvalid("superclass not a reference type", Superclass);
12371237
continue;
12381238
}
12391239

@@ -1252,7 +1252,7 @@ class ExistentialTypeInfoBuilder {
12521252
case FieldDescriptorKind::Enum:
12531253
case FieldDescriptorKind::MultiPayloadEnum:
12541254
case FieldDescriptorKind::Class:
1255-
Invalid = true;
1255+
markInvalid("unexpected field descriptor kind");
12561256
continue;
12571257
}
12581258
}
@@ -1283,8 +1283,7 @@ class ExistentialTypeInfoBuilder {
12831283
if (!isa<NominalTypeRef>(T) &&
12841284
!isa<BoundGenericTypeRef>(T) &&
12851285
!isa<ObjCClassTypeRef>(T)) {
1286-
DEBUG_LOG(fprintf(stderr, "Bad existential member: "); T->dump())
1287-
Invalid = true;
1286+
markInvalid("bad existential member", T);
12881287
return;
12891288
}
12901289

@@ -1296,8 +1295,7 @@ class ExistentialTypeInfoBuilder {
12961295

12971296
const auto &FD = TC.getBuilder().getFieldDescriptor(T);
12981297
if (FD == nullptr) {
1299-
DEBUG_LOG(fprintf(stderr, "No field descriptor: "); T->dump())
1300-
Invalid = true;
1298+
markInvalid("no field descriptor", T);
13011299
return;
13021300
}
13031301

@@ -1313,8 +1311,7 @@ class ExistentialTypeInfoBuilder {
13131311
break;
13141312

13151313
default:
1316-
DEBUG_LOG(fprintf(stderr, "Bad existential member: "); T->dump())
1317-
Invalid = true;
1314+
markInvalid("bad existential member", T);
13181315
return;
13191316
}
13201317
}
@@ -1324,10 +1321,6 @@ class ExistentialTypeInfoBuilder {
13241321
Representation = ExistentialTypeRepresentation::Class;
13251322
}
13261323

1327-
void markInvalid() {
1328-
Invalid = true;
1329-
}
1330-
13311324
const TypeInfo *build(remote::TypeInfoProvider *ExternalTypeInfo) {
13321325
examineProtocols();
13331326

@@ -1407,7 +1400,7 @@ class ExistentialTypeInfoBuilder {
14071400

14081401
if (ObjC) {
14091402
if (WitnessTableCount > 0) {
1410-
DEBUG_LOG(fprintf(stderr, "@objc existential with witness tables\n"));
1403+
markInvalid("@objc existential with witness tables");
14111404
return nullptr;
14121405
}
14131406

@@ -1480,8 +1473,7 @@ void RecordTypeInfoBuilder::addField(
14801473
remote::TypeInfoProvider *ExternalTypeInfo) {
14811474
const TypeInfo *TI = TC.getTypeInfo(TR, ExternalTypeInfo);
14821475
if (TI == nullptr) {
1483-
DEBUG_LOG(fprintf(stderr, "No TypeInfo for field type: "); TR->dump());
1484-
Invalid = true;
1476+
markInvalid("no TypeInfo for field type", TR);
14851477
return;
14861478
}
14871479

@@ -1563,6 +1555,18 @@ const ReferenceTypeInfo *TypeConverter::getReferenceTypeInfo(
15631555
return TI;
15641556
}
15651557

1558+
std::string TypeConverter::takeLastError() {
1559+
if (!LastError.first)
1560+
return {};
1561+
std::stringstream s;
1562+
s << ": " << LastError.first;
1563+
if (LastError.second)
1564+
LastError.second->dump(s);
1565+
1566+
LastError = {nullptr, nullptr};
1567+
return s.str();
1568+
}
1569+
15661570
/// Thin functions consist of a function pointer. We do not use
15671571
/// Builtin.RawPointer here, since the extra inhabitants differ.
15681572
const TypeInfo *
@@ -1996,6 +2000,12 @@ class EnumTypeInfoBuilder {
19962000
std::vector<FieldInfo> Cases;
19972001
bool Invalid;
19982002

2003+
void markInvalid(const char *msg, const TypeRef *TR = nullptr) {
2004+
Invalid = true;
2005+
DEBUG_LOG(fprintf(stderr, "%s\n", msg); if (TR) TR->dump());
2006+
TC.setError(msg, TR);
2007+
}
2008+
19992009
const TypeRef *getCaseTypeRef(FieldTypeInfo Case) {
20002010
// An indirect case is like a payload case with an argument type
20012011
// of Builtin.NativeObject.
@@ -2015,8 +2025,7 @@ class EnumTypeInfoBuilder {
20152025
void addCase(const std::string &Name, const TypeRef *TR,
20162026
const TypeInfo *TI) {
20172027
if (TI == nullptr) {
2018-
DEBUG_LOG(fprintf(stderr, "No TypeInfo for case type: "); TR->dump());
2019-
Invalid = true;
2028+
markInvalid("no type info for case type", TR);
20202029
static TypeInfo emptyTI;
20212030
Cases.push_back({Name, /*offset=*/0, /*value=*/-1, TR, emptyTI});
20222031
} else {
@@ -2045,7 +2054,7 @@ class EnumTypeInfoBuilder {
20452054

20462055
std::vector<FieldTypeInfo> Fields;
20472056
if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) {
2048-
Invalid = true;
2057+
markInvalid("cannot not get field types", TR);
20492058
return nullptr;
20502059
}
20512060

@@ -2060,7 +2069,7 @@ class EnumTypeInfoBuilder {
20602069
auto *CaseTI = TC.getTypeInfo(CaseTR, ExternalTypeInfo);
20612070
if (CaseTI == nullptr) {
20622071
// We don't have typeinfo; something is very broken.
2063-
Invalid = true;
2072+
markInvalid("no type info for single enum case", CaseTR);
20642073
return nullptr;
20652074
} else if (Case.Indirect) {
20662075
// An indirect case is non-empty (it stores a pointer)
@@ -2655,8 +2664,11 @@ TypeConverter::getTypeInfo(const TypeRef *TR,
26552664
ExternalTypeInfo ? ExternalTypeInfo->getId() : 0;
26562665
// See if we already computed the result
26572666
auto found = Cache.find({TR, ExternalTypeInfoId});
2658-
if (found != Cache.end())
2667+
if (found != Cache.end()) {
2668+
if (!found->second && ErrorCache)
2669+
LastError = ErrorCache->lookup({TR, ExternalTypeInfoId});
26592670
return found->second;
2671+
}
26602672

26612673
// Detect invalid recursive value types (IRGen should not emit
26622674
// them in the first place, but there might be bugs)
@@ -2668,6 +2680,8 @@ TypeConverter::getTypeInfo(const TypeRef *TR,
26682680
// Compute the result and cache it
26692681
auto *TI = LowerType(*this, ExternalTypeInfo).visit(TR);
26702682
Cache.insert({{TR, ExternalTypeInfoId}, TI});
2683+
if (!TI && ErrorCache)
2684+
ErrorCache->insert({{TR, ExternalTypeInfoId}, LastError});
26712685

26722686
RecursionCheck.erase(TR);
26732687

0 commit comments

Comments
 (0)