Skip to content

Commit a7f3607

Browse files
authored
Merge pull request swiftlang#17571 from dcci/existentialremoteast
[RemoteAST] Initial support for projecting the type out of an existen…
2 parents 423bee6 + 4b5c229 commit a7f3607

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"
@@ -808,6 +809,9 @@ class RemoteASTContextImpl {
808809
getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0;
809810
virtual Result<RemoteAddress>
810811
getHeapMetadataForObject(RemoteAddress object) = 0;
812+
virtual Result<std::pair<Type, RemoteAddress>>
813+
getDynamicTypeAndAddressForExistential(RemoteAddress object,
814+
Type staticType) = 0;
811815

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

11651248
} // end anonymous namespace
@@ -1217,3 +1300,10 @@ Result<remote::RemoteAddress>
12171300
RemoteASTContext::getHeapMetadataForObject(remote::RemoteAddress address) {
12181301
return asImpl(Impl)->getHeapMetadataForObject(address);
12191302
}
1303+
1304+
Result<std::pair<Type, remote::RemoteAddress>>
1305+
RemoteASTContext::getDynamicTypeAndAddressForExistential(
1306+
remote::RemoteAddress address, Type staticType) {
1307+
return asImpl(Impl)->getDynamicTypeAndAddressForExistential(address,
1308+
staticType);
1309+
}

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)