mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #17571 from dcci/existentialremoteast
[RemoteAST] Initial support for projecting the type out of an existen…
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
46
test/RemoteAST/existentials.swift
Normal file
46
test/RemoteAST/existentials.swift
Normal 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)
|
||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user