Skip to content

Commit 4b5c229

Browse files
author
Davide Italiano
committed
[RemoteAST] Support for extracting the type/valuea out of an existential.
This will be used in lldb. <rdar://problem/41546568>
1 parent 7934190 commit 4b5c229

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,14 @@ class MetadataReader {
264264
return start;
265265
}
266266

267+
/// Given a pointer to an address, attemp to read the pointed value.
268+
llvm::Optional<StoredPointer> readPointedValue(StoredPointer Address) {
269+
StoredPointer PointedVal;
270+
if (!Reader->readInteger(RemoteAddress(Address), &PointedVal))
271+
return llvm::None;
272+
return llvm::Optional<StoredPointer>(PointedVal);
273+
}
274+
267275
/// Given a pointer to the metadata, attempt to read the value
268276
/// witness table. Note that it's not safe to access any non-mandatory
269277
/// members of the value witness table, like extra inhabitants or enum members.

include/swift/RemoteAST/RemoteAST.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ class RemoteASTContext {
211211
/// Given a heap object, resolve its heap metadata.
212212
Result<remote::RemoteAddress>
213213
getHeapMetadataForObject(remote::RemoteAddress address);
214+
215+
/// Given an existential and its static type, resolve its dynamic
216+
/// type and address. A single step of unwrapping is performed, i.e. if the
217+
/// value stored inside the existential is itself an existential, the
218+
/// caller can decide whether to iterate itself.
219+
Result<std::pair<Type, remote::RemoteAddress>>
220+
getDynamicTypeAndAddressForExistential(remote::RemoteAddress address,
221+
Type staticType);
214222
};
215223

216224
} // end namespace remoteAST

lib/RemoteAST/RemoteAST.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/Subsystems.h"
2121
#include "swift/AST/ASTContext.h"
2222
#include "swift/AST/Decl.h"
23+
#include "swift/AST/ExistentialLayout.h"
2324
#include "swift/AST/GenericSignature.h"
2425
#include "swift/AST/Module.h"
2526
#include "swift/AST/NameLookup.h"
@@ -810,6 +811,9 @@ class RemoteASTContextImpl {
810811
getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0;
811812
virtual Result<RemoteAddress>
812813
getHeapMetadataForObject(RemoteAddress object) = 0;
814+
virtual Result<std::pair<Type, RemoteAddress>>
815+
getDynamicTypeAndAddressForExistential(RemoteAddress object,
816+
Type staticType) = 0;
813817

814818
Result<uint64_t>
815819
getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName){
@@ -1162,6 +1166,85 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl {
11621166
if (result) return RemoteAddress(*result);
11631167
return getFailure<RemoteAddress>();
11641168
}
1169+
1170+
Result<std::pair<Type, RemoteAddress>>
1171+
getDynamicTypeAndAddressClassExistential(RemoteAddress object) {
1172+
auto pointed = Reader.readPointedValue(object.getAddressData());
1173+
if (!pointed)
1174+
return getFailure<std::pair<Type, RemoteAddress>>();
1175+
auto result = Reader.readMetadataFromInstance(*pointed);
1176+
if (!result)
1177+
return getFailure<std::pair<Type, RemoteAddress>>();
1178+
auto typeResult = Reader.readTypeFromMetadata(result.getValue());
1179+
if (!typeResult)
1180+
return getFailure<std::pair<Type, RemoteAddress>>();
1181+
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
1182+
std::move(object));
1183+
}
1184+
1185+
Result<std::pair<Type, RemoteAddress>>
1186+
getDynamicTypeAndAddressErrorExistential(RemoteAddress object) {
1187+
auto pointed = Reader.readPointedValue(object.getAddressData());
1188+
if (!pointed)
1189+
return getFailure<std::pair<Type, RemoteAddress>>();
1190+
auto result =
1191+
Reader.readMetadataAndValueErrorExistential(RemoteAddress(*pointed));
1192+
if (!result)
1193+
return getFailure<std::pair<Type, RemoteAddress>>();
1194+
RemoteAddress metadataAddress = result->first;
1195+
RemoteAddress valueAddress = result->second;
1196+
1197+
auto typeResult =
1198+
Reader.readTypeFromMetadata(metadataAddress.getAddressData());
1199+
if (!typeResult)
1200+
return getFailure<std::pair<Type, RemoteAddress>>();
1201+
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
1202+
std::move(valueAddress));
1203+
}
1204+
1205+
Result<std::pair<Type, RemoteAddress>>
1206+
getDynamicTypeAndAddressOpaqueExistential(RemoteAddress object) {
1207+
auto result = Reader.readMetadataAndValueOpaqueExistential(object);
1208+
if (!result)
1209+
return getFailure<std::pair<Type, RemoteAddress>>();
1210+
RemoteAddress metadataAddress = result->first;
1211+
RemoteAddress valueAddress = result->second;
1212+
1213+
auto typeResult =
1214+
Reader.readTypeFromMetadata(metadataAddress.getAddressData());
1215+
if (!typeResult)
1216+
return getFailure<std::pair<Type, RemoteAddress>>();
1217+
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
1218+
std::move(valueAddress));
1219+
}
1220+
1221+
/// Resolve the dynamic type and the value address of an existential,
1222+
/// given its address and its static type. For class and error existentials,
1223+
/// this API takes a pointer to the instance reference rather than the
1224+
/// instance reference itself.
1225+
Result<std::pair<Type, RemoteAddress>>
1226+
getDynamicTypeAndAddressForExistential(RemoteAddress object,
1227+
Type staticType) override {
1228+
// If this is not an existential, give up.
1229+
if (!staticType->isAnyExistentialType())
1230+
return getFailure<std::pair<Type, RemoteAddress>>();
1231+
1232+
// TODO: implement support for ExistentialMetaTypes.
1233+
if (!staticType->isExistentialType())
1234+
return getFailure<std::pair<Type, RemoteAddress>>();
1235+
1236+
// This should be an existential type at this point.
1237+
auto layout = staticType->getExistentialLayout();
1238+
switch (layout.getKind()) {
1239+
case ExistentialLayout::Kind::Class:
1240+
return getDynamicTypeAndAddressClassExistential(object);
1241+
case ExistentialLayout::Kind::Error:
1242+
return getDynamicTypeAndAddressErrorExistential(object);
1243+
case ExistentialLayout::Kind::Opaque:
1244+
return getDynamicTypeAndAddressOpaqueExistential(object);
1245+
}
1246+
llvm_unreachable("invalid type kind");
1247+
}
11651248
};
11661249

11671250
} // end anonymous namespace
@@ -1219,3 +1302,10 @@ Result<remote::RemoteAddress>
12191302
RemoteASTContext::getHeapMetadataForObject(remote::RemoteAddress address) {
12201303
return asImpl(Impl)->getHeapMetadataForObject(address);
12211304
}
1305+
1306+
Result<std::pair<Type, remote::RemoteAddress>>
1307+
RemoteASTContext::getDynamicTypeAndAddressForExistential(
1308+
remote::RemoteAddress address, Type staticType) {
1309+
return asImpl(Impl)->getDynamicTypeAndAddressForExistential(address,
1310+
staticType);
1311+
}

test/RemoteAST/existentials.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %target-swift-remoteast-test %s | %FileCheck %s
2+
3+
// REQUIRES: swift-remoteast-test
4+
5+
@_silgen_name("printDynamicTypeAndAddressForExistential")
6+
func printDynamicTypeAndAddressForExistential<T>(_: T)
7+
8+
struct MyStruct<T, U, V> {
9+
let x: T
10+
let y: U
11+
let z: V
12+
}
13+
14+
// Case one, small opaque (fits into the inline buffer).
15+
// CHECK: MyStruct<Int, Int, Int>
16+
let smallStruct = MyStruct(x : 1, y: 2, z: 3)
17+
printDynamicTypeAndAddressForExistential(smallStruct as Any)
18+
19+
// Case two, large opaque (boxed representation).
20+
// CHECK-NEXT: MyStruct<(Int, Int, Int), (Int, Int, Int), (Int, Int, Int)>
21+
let largeStruct = MyStruct(x: (1,1,1), y: (2,2,2), z: (3,3,3))
22+
printDynamicTypeAndAddressForExistential(largeStruct as Any)
23+
24+
class MyClass<T, U> {
25+
let x: T
26+
let y: (T, U)
27+
init(x: T, y: (T, U)) {
28+
self.x = x
29+
self.y = y
30+
}
31+
}
32+
33+
// Case three, class existential (adheres to AnyObject protocol).a
34+
// CHECK-NEXT: MyClass<Int, Int>
35+
let mc = MyClass(x : 23, y : (42, 44)) as AnyObject
36+
printDynamicTypeAndAddressForExistential(mc)
37+
38+
enum MyError : Error {
39+
case a
40+
case b
41+
}
42+
43+
// Case four: error existential.
44+
// CHECK-NEXT: MyError
45+
let q : Error = MyError.a
46+
printDynamicTypeAndAddressForExistential(q)

tools/swift-remoteast-test/swift-remoteast-test.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/Basic/LLVM.h"
2222
#include "swift/Basic/LLVMInitialize.h"
2323
#include "llvm/ADT/SmallVector.h"
24+
#include "llvm/Support/Format.h"
2425
#include "llvm/Support/raw_ostream.h"
2526
#include <cassert>
2627

@@ -141,6 +142,39 @@ extern "C" void printTypeMetadataMemberOffset(const Metadata *typeMetadata,
141142
printMemberOffset(typeMetadata, memberName, /*pass metadata*/ true);
142143
}
143144

145+
// FIXME: swiftcall
146+
/// func printDynamicTypeAndAddressForExistential<T>(_: T)
147+
LLVM_ATTRIBUTE_USED SWIFT_REMOTEAST_TEST_ABI extern "C" void
148+
printDynamicTypeAndAddressForExistential(void *object,
149+
const Metadata *typeMetadata) {
150+
assert(Context && "context was not set");
151+
std::shared_ptr<MemoryReader> reader(new InProcessMemoryReader());
152+
RemoteASTContext remoteAST(*Context, std::move(reader));
153+
154+
auto &out = llvm::outs();
155+
156+
// First, retrieve the static type of the existential, so we can understand
157+
// which kind of existential this is.
158+
auto staticTypeResult =
159+
remoteAST.getTypeForRemoteTypeMetadata(RemoteAddress(typeMetadata));
160+
if (!staticTypeResult) {
161+
out << "failed to resolve static type: "
162+
<< staticTypeResult.getFailure().render() << '\n';
163+
return;
164+
}
165+
166+
// OK, we can reconstruct the dynamic type and the address now.
167+
auto result = remoteAST.getDynamicTypeAndAddressForExistential(
168+
RemoteAddress(object), staticTypeResult.getValue());
169+
if (result) {
170+
out << "found type: ";
171+
result.getValue().first.print(out);
172+
out << "\n";
173+
} else {
174+
out << result.getFailure().render() << '\n';
175+
}
176+
}
177+
144178
namespace {
145179

146180
struct Observer : public FrontendObserver {

0 commit comments

Comments
 (0)