Merge pull request #17571 from dcci/existentialremoteast

[RemoteAST] Initial support for projecting the type out of an existen…
This commit is contained in:
Davide Italiano
2018-07-31 14:27:50 -07:00
committed by GitHub
5 changed files with 186 additions and 0 deletions

View File

@@ -264,6 +264,14 @@ public:
return start; return start;
} }
/// Given a pointer to an address, attemp to read the pointed value.
llvm::Optional<StoredPointer> readPointedValue(StoredPointer Address) {
StoredPointer PointedVal;
if (!Reader->readInteger(RemoteAddress(Address), &PointedVal))
return llvm::None;
return llvm::Optional<StoredPointer>(PointedVal);
}
/// Given a pointer to the metadata, attempt to read the value /// Given a pointer to the metadata, attempt to read the value
/// witness table. Note that it's not safe to access any non-mandatory /// witness table. Note that it's not safe to access any non-mandatory
/// members of the value witness table, like extra inhabitants or enum members. /// members of the value witness table, like extra inhabitants or enum members.

View File

@@ -211,6 +211,14 @@ public:
/// Given a heap object, resolve its heap metadata. /// Given a heap object, resolve its heap metadata.
Result<remote::RemoteAddress> Result<remote::RemoteAddress>
getHeapMetadataForObject(remote::RemoteAddress address); getHeapMetadataForObject(remote::RemoteAddress address);
/// Given an existential and its static type, resolve its dynamic
/// type and address. A single step of unwrapping is performed, i.e. if the
/// value stored inside the existential is itself an existential, the
/// caller can decide whether to iterate itself.
Result<std::pair<Type, remote::RemoteAddress>>
getDynamicTypeAndAddressForExistential(remote::RemoteAddress address,
Type staticType);
}; };
} // end namespace remoteAST } // end namespace remoteAST

View File

@@ -20,6 +20,7 @@
#include "swift/Subsystems.h" #include "swift/Subsystems.h"
#include "swift/AST/ASTContext.h" #include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h" #include "swift/AST/Decl.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericSignature.h" #include "swift/AST/GenericSignature.h"
#include "swift/AST/Module.h" #include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h" #include "swift/AST/NameLookup.h"
@@ -808,6 +809,9 @@ public:
getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0; getDeclForRemoteNominalTypeDescriptor(RemoteAddress descriptor) = 0;
virtual Result<RemoteAddress> virtual Result<RemoteAddress>
getHeapMetadataForObject(RemoteAddress object) = 0; getHeapMetadataForObject(RemoteAddress object) = 0;
virtual Result<std::pair<Type, RemoteAddress>>
getDynamicTypeAndAddressForExistential(RemoteAddress object,
Type staticType) = 0;
Result<uint64_t> Result<uint64_t>
getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName){ getOffsetOfMember(Type type, RemoteAddress optMetadata, StringRef memberName){
@@ -1160,6 +1164,85 @@ public:
if (result) return RemoteAddress(*result); if (result) return RemoteAddress(*result);
return getFailure<RemoteAddress>(); return getFailure<RemoteAddress>();
} }
Result<std::pair<Type, RemoteAddress>>
getDynamicTypeAndAddressClassExistential(RemoteAddress object) {
auto pointed = Reader.readPointedValue(object.getAddressData());
if (!pointed)
return getFailure<std::pair<Type, RemoteAddress>>();
auto result = Reader.readMetadataFromInstance(*pointed);
if (!result)
return getFailure<std::pair<Type, RemoteAddress>>();
auto typeResult = Reader.readTypeFromMetadata(result.getValue());
if (!typeResult)
return getFailure<std::pair<Type, RemoteAddress>>();
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
std::move(object));
}
Result<std::pair<Type, RemoteAddress>>
getDynamicTypeAndAddressErrorExistential(RemoteAddress object) {
auto pointed = Reader.readPointedValue(object.getAddressData());
if (!pointed)
return getFailure<std::pair<Type, RemoteAddress>>();
auto result =
Reader.readMetadataAndValueErrorExistential(RemoteAddress(*pointed));
if (!result)
return getFailure<std::pair<Type, RemoteAddress>>();
RemoteAddress metadataAddress = result->first;
RemoteAddress valueAddress = result->second;
auto typeResult =
Reader.readTypeFromMetadata(metadataAddress.getAddressData());
if (!typeResult)
return getFailure<std::pair<Type, RemoteAddress>>();
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
std::move(valueAddress));
}
Result<std::pair<Type, RemoteAddress>>
getDynamicTypeAndAddressOpaqueExistential(RemoteAddress object) {
auto result = Reader.readMetadataAndValueOpaqueExistential(object);
if (!result)
return getFailure<std::pair<Type, RemoteAddress>>();
RemoteAddress metadataAddress = result->first;
RemoteAddress valueAddress = result->second;
auto typeResult =
Reader.readTypeFromMetadata(metadataAddress.getAddressData());
if (!typeResult)
return getFailure<std::pair<Type, RemoteAddress>>();
return std::make_pair<Type, RemoteAddress>(std::move(typeResult),
std::move(valueAddress));
}
/// Resolve the dynamic type and the value address of an existential,
/// given its address and its static type. For class and error existentials,
/// this API takes a pointer to the instance reference rather than the
/// instance reference itself.
Result<std::pair<Type, RemoteAddress>>
getDynamicTypeAndAddressForExistential(RemoteAddress object,
Type staticType) override {
// If this is not an existential, give up.
if (!staticType->isAnyExistentialType())
return getFailure<std::pair<Type, RemoteAddress>>();
// TODO: implement support for ExistentialMetaTypes.
if (!staticType->isExistentialType())
return getFailure<std::pair<Type, RemoteAddress>>();
// This should be an existential type at this point.
auto layout = staticType->getExistentialLayout();
switch (layout.getKind()) {
case ExistentialLayout::Kind::Class:
return getDynamicTypeAndAddressClassExistential(object);
case ExistentialLayout::Kind::Error:
return getDynamicTypeAndAddressErrorExistential(object);
case ExistentialLayout::Kind::Opaque:
return getDynamicTypeAndAddressOpaqueExistential(object);
}
llvm_unreachable("invalid type kind");
}
}; };
} // end anonymous namespace } // end anonymous namespace
@@ -1217,3 +1300,10 @@ Result<remote::RemoteAddress>
RemoteASTContext::getHeapMetadataForObject(remote::RemoteAddress address) { RemoteASTContext::getHeapMetadataForObject(remote::RemoteAddress address) {
return asImpl(Impl)->getHeapMetadataForObject(address); return asImpl(Impl)->getHeapMetadataForObject(address);
} }
Result<std::pair<Type, remote::RemoteAddress>>
RemoteASTContext::getDynamicTypeAndAddressForExistential(
remote::RemoteAddress address, Type staticType) {
return asImpl(Impl)->getDynamicTypeAndAddressForExistential(address,
staticType);
}

View File

@@ -0,0 +1,46 @@
// RUN: %target-swift-remoteast-test %s | %FileCheck %s
// REQUIRES: swift-remoteast-test
@_silgen_name("printDynamicTypeAndAddressForExistential")
func printDynamicTypeAndAddressForExistential<T>(_: T)
struct MyStruct<T, U, V> {
let x: T
let y: U
let z: V
}
// Case one, small opaque (fits into the inline buffer).
// CHECK: MyStruct<Int, Int, Int>
let smallStruct = MyStruct(x : 1, y: 2, z: 3)
printDynamicTypeAndAddressForExistential(smallStruct as Any)
// Case two, large opaque (boxed representation).
// CHECK-NEXT: MyStruct<(Int, Int, Int), (Int, Int, Int), (Int, Int, Int)>
let largeStruct = MyStruct(x: (1,1,1), y: (2,2,2), z: (3,3,3))
printDynamicTypeAndAddressForExistential(largeStruct as Any)
class MyClass<T, U> {
let x: T
let y: (T, U)
init(x: T, y: (T, U)) {
self.x = x
self.y = y
}
}
// Case three, class existential (adheres to AnyObject protocol).a
// CHECK-NEXT: MyClass<Int, Int>
let mc = MyClass(x : 23, y : (42, 44)) as AnyObject
printDynamicTypeAndAddressForExistential(mc)
enum MyError : Error {
case a
case b
}
// Case four: error existential.
// CHECK-NEXT: MyError
let q : Error = MyError.a
printDynamicTypeAndAddressForExistential(q)

View File

@@ -21,6 +21,7 @@
#include "swift/Basic/LLVM.h" #include "swift/Basic/LLVM.h"
#include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/LLVMInitialize.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <cassert> #include <cassert>
@@ -141,6 +142,39 @@ extern "C" void printTypeMetadataMemberOffset(const Metadata *typeMetadata,
printMemberOffset(typeMetadata, memberName, /*pass metadata*/ true); printMemberOffset(typeMetadata, memberName, /*pass metadata*/ true);
} }
// FIXME: swiftcall
/// func printDynamicTypeAndAddressForExistential<T>(_: T)
LLVM_ATTRIBUTE_USED SWIFT_REMOTEAST_TEST_ABI extern "C" void
printDynamicTypeAndAddressForExistential(void *object,
const Metadata *typeMetadata) {
assert(Context && "context was not set");
std::shared_ptr<MemoryReader> reader(new InProcessMemoryReader());
RemoteASTContext remoteAST(*Context, std::move(reader));
auto &out = llvm::outs();
// First, retrieve the static type of the existential, so we can understand
// which kind of existential this is.
auto staticTypeResult =
remoteAST.getTypeForRemoteTypeMetadata(RemoteAddress(typeMetadata));
if (!staticTypeResult) {
out << "failed to resolve static type: "
<< staticTypeResult.getFailure().render() << '\n';
return;
}
// OK, we can reconstruct the dynamic type and the address now.
auto result = remoteAST.getDynamicTypeAndAddressForExistential(
RemoteAddress(object), staticTypeResult.getValue());
if (result) {
out << "found type: ";
result.getValue().first.print(out);
out << "\n";
} else {
out << result.getFailure().render() << '\n';
}
}
namespace { namespace {
struct Observer : public FrontendObserver { struct Observer : public FrontendObserver {