Skip to content

Commit 12a774a

Browse files
committed
[Runtime] Fill in the superclass of foreign class metadata.
When emitting foreign class metadata (e.g., for an imported CF type), fill in the superclass when we have one. The superclass will itself be a foreign metadata candidate, so also register an initialization function that uniques the superclass metadata once we've picked the canonical foreign class metadata.
1 parent 7458640 commit 12a774a

File tree

8 files changed

+271
-73
lines changed

8 files changed

+271
-73
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===-- ForeignClassMetadataVisitor.h - foreign class metadata -*- C++ --*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// A CRTP class useful for laying out foreign class metadata.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H
18+
#define SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H
19+
20+
#include "NominalMetadataVisitor.h"
21+
22+
namespace swift {
23+
namespace irgen {
24+
25+
/// A CRTP layout class for foreign class metadata.
26+
template <class Impl>
27+
class ForeignClassMetadataVisitor
28+
: public NominalMetadataVisitor<Impl> {
29+
using super = NominalMetadataVisitor<Impl>;
30+
protected:
31+
ClassDecl *Target;
32+
using super::asImpl;
33+
public:
34+
ForeignClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
35+
: super(IGM), Target(target) {}
36+
37+
void layout() {
38+
super::layout();
39+
asImpl().addNominalTypeDescriptor();
40+
asImpl().noteStartOfSuperClass();
41+
asImpl().addSuperClass();
42+
asImpl().addReservedWord();
43+
asImpl().addReservedWord();
44+
asImpl().addReservedWord();
45+
}
46+
47+
bool requiresInitializationFunction() {
48+
return Target->getSuperclassDecl() &&
49+
Target->getSuperclassDecl()->isForeign();
50+
}
51+
52+
CanType getTargetType() const {
53+
return Target->getDeclaredType()->getCanonicalType();
54+
}
55+
};
56+
57+
/// An "implementation" of ForeignClassMetadataVisitor that just scans through
58+
/// the metadata layout, maintaining the offset of the next field.
59+
template <class Impl>
60+
class ForeignClassMetadataScanner : public ForeignClassMetadataVisitor<Impl> {
61+
typedef ForeignClassMetadataVisitor<Impl> super;
62+
protected:
63+
Size NextOffset = Size(0);
64+
65+
ForeignClassMetadataScanner(IRGenModule &IGM, ClassDecl *target)
66+
: super(IGM, target) {}
67+
68+
public:
69+
void addMetadataFlags() { addPointer(); }
70+
void addValueWitnessTable() { addPointer(); }
71+
void addNominalTypeDescriptor() { addPointer(); }
72+
void addSuperClass() { addPointer(); }
73+
void addReservedWord() { addPointer(); }
74+
75+
private:
76+
void addPointer() {
77+
NextOffset += super::IGM.getPointerSize();
78+
}
79+
};
80+
81+
} // end namespace irgen
82+
} // end namespace swift
83+
84+
#endif // SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H

lib/IRGen/GenKeyPath.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,11 +903,11 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
903903
} else {
904904
idKind = KeyPathComponentHeader::VTableOffset;
905905
auto dc = declRef.getDecl()->getDeclContext();
906-
if (isa<ClassDecl>(dc)) {
906+
if (isa<ClassDecl>(dc) && !cast<ClassDecl>(dc)->isForeign()) {
907907
auto overridden = declRef.getOverriddenVTableEntry();
908908
auto declaringClass =
909909
cast<ClassDecl>(overridden.getDecl()->getDeclContext());
910-
auto &metadataLayout = getMetadataLayout(declaringClass);
910+
auto &metadataLayout = getClassMetadataLayout(declaringClass);
911911
// FIXME: Resilience. We don't want vtable layout to be ABI, so this
912912
// should be encoded as a reference to the method dispatch thunk
913913
// instead.

lib/IRGen/GenMeta.cpp

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "ConstantBuilder.h"
4242
#include "EnumMetadataVisitor.h"
4343
#include "FixedTypeInfo.h"
44+
#include "ForeignClassMetadataVisitor.h"
4445
#include "GenArchetype.h"
4546
#include "GenClass.h"
4647
#include "GenDecl.h"
@@ -296,18 +297,24 @@ llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF,
296297
}
297298

298299
/// Emit a reference to the type metadata for a foreign type.
299-
static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF,
300-
CanType type) {
301-
llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type);
300+
static llvm::Value *uniqueForeignTypeMetadataRef(IRGenFunction &IGF,
301+
llvm::Value *candidate) {
302302
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetForeignTypeMetadataFn(),
303-
candidate);
303+
candidate);
304304
call->addAttribute(llvm::AttributeList::FunctionIndex,
305305
llvm::Attribute::NoUnwind);
306306
call->addAttribute(llvm::AttributeList::FunctionIndex,
307307
llvm::Attribute::ReadNone);
308308
return call;
309309
}
310310

311+
/// Emit a reference to the type metadata for a foreign type.
312+
static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF,
313+
CanType type) {
314+
llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type);
315+
return uniqueForeignTypeMetadataRef(IGF, candidate);
316+
}
317+
311318
/// Returns a metadata reference for a nominal type.
312319
///
313320
/// This is only valid in a couple of special cases:
@@ -2189,11 +2196,13 @@ namespace {
21892196
// GenericParameterDescriptorFlags Flags;
21902197
GenericParameterDescriptorFlags flags;
21912198
if (auto *cd = dyn_cast<ClassDecl>(ntd)) {
2192-
auto &layout = IGM.getMetadataLayout(cd);
2193-
if (layout.getVTableSize() > 0)
2194-
flags = flags.withHasVTable(true);
2195-
if (layout.hasResilientSuperclass())
2196-
flags = flags.withHasResilientSuperclass(true);
2199+
if (!cd->isForeign()) {
2200+
auto &layout = IGM.getClassMetadataLayout(cd);
2201+
if (layout.getVTableSize() > 0)
2202+
flags = flags.withHasVTable(true);
2203+
if (layout.hasResilientSuperclass())
2204+
flags = flags.withHasResilientSuperclass(true);
2205+
}
21972206
}
21982207

21992208
// Calculate the number of generic parameters at each nesting depth.
@@ -2428,7 +2437,13 @@ namespace {
24282437
ClassDecl *c)
24292438
: super(IGM), Target(c)
24302439
{
2431-
auto &layout = IGM.getMetadataLayout(Target);
2440+
if (Target->isForeign()) {
2441+
VTable = nullptr;
2442+
VTableSize = 0;
2443+
return;
2444+
}
2445+
2446+
auto &layout = IGM.getClassMetadataLayout(Target);
24322447

24332448
VTable = IGM.getSILModule().lookUpVTable(Target);
24342449
VTableSize = layout.getVTableSize();
@@ -2834,7 +2849,7 @@ namespace {
28342849
// fill indexes are word-indexed.
28352850
auto *metadataWords = IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy);
28362851

2837-
auto genericReqtOffset = IGM.getMetadataLayout(Target)
2852+
auto genericReqtOffset = IGM.getNominalMetadataLayout(Target)
28382853
.getGenericRequirementsOffset(IGF);
28392854

28402855
for (auto &fillOp : FillOps) {
@@ -3145,7 +3160,7 @@ namespace {
31453160
auto fn = entry.Method;
31463161

31473162
auto *classDecl = cast<ClassDecl>(fn.getDecl()->getDeclContext());
3148-
auto &layout = IGM.getMetadataLayout(classDecl);
3163+
auto &layout = IGM.getClassMetadataLayout(classDecl);
31493164

31503165
auto offset = layout.getMethodInfo(IGF, fn).getOffset();
31513166

@@ -3493,7 +3508,7 @@ namespace {
34933508
if (!HasResilientSuperclass)
34943509
return;
34953510

3496-
auto &layout = IGM.getMetadataLayout(Target);
3511+
auto &layout = IGM.getClassMetadataLayout(Target);
34973512

34983513
// Load the size of the superclass metadata.
34993514
Address metadataAsBytes(
@@ -3747,7 +3762,7 @@ namespace {
37473762
if (doesClassMetadataRequireDynamicInitialization(IGM, Target)) {
37483763
auto templateSize = IGM.getSize(Size(B.getNextOffsetFromGlobal()));
37493764
auto numImmediateMembers = IGM.getSize(
3750-
Size(IGM.getMetadataLayout(Target).getNumImmediateMembers()));
3765+
Size(IGM.getClassMetadataLayout(Target).getNumImmediateMembers()));
37513766
metadata = IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(),
37523767
{metadata, templateSize,
37533768
numImmediateMembers});
@@ -3838,7 +3853,7 @@ namespace {
38383853
}
38393854

38403855
auto numImmediateMembers =
3841-
IGM.getSize(Size(IGM.getMetadataLayout(Target).getNumImmediateMembers()));
3856+
IGM.getSize(Size(IGM.getClassMetadataLayout(Target).getNumImmediateMembers()));
38423857

38433858
return IGF.Builder.CreateCall(IGM.getAllocateGenericClassMetadataFn(),
38443859
{metadataPattern, arguments, superMetadata,
@@ -4230,7 +4245,7 @@ std::pair<llvm::Value *, llvm::Value *>
42304245
irgen::emitClassResilientInstanceSizeAndAlignMask(IRGenFunction &IGF,
42314246
ClassDecl *theClass,
42324247
llvm::Value *metadata) {
4233-
auto &layout = IGF.IGM.getMetadataLayout(theClass);
4248+
auto &layout = IGF.IGM.getClassMetadataLayout(theClass);
42344249

42354250
Address metadataAsBytes(IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrTy),
42364251
IGF.IGM.getPointerAlignment());
@@ -4487,7 +4502,7 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
44874502
auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
44884503

44894504
auto methodInfo =
4490-
IGF.IGM.getMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
4505+
IGF.IGM.getClassMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
44914506
auto offset = methodInfo.getOffset();
44924507

44934508
auto slot = IGF.emitAddressAtOffset(metadata, offset,
@@ -4887,37 +4902,6 @@ llvm::Value *IRGenFunction::emitObjCSelectorRefLoad(StringRef selector) {
48874902
//===----------------------------------------------------------------------===//
48884903

48894904
namespace {
4890-
/// A CRTP layout class for foreign class metadata.
4891-
template <class Impl>
4892-
class ForeignClassMetadataVisitor
4893-
: public NominalMetadataVisitor<Impl> {
4894-
using super = NominalMetadataVisitor<Impl>;
4895-
protected:
4896-
ClassDecl *Target;
4897-
using super::asImpl;
4898-
public:
4899-
ForeignClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
4900-
: super(IGM), Target(target) {}
4901-
4902-
void layout() {
4903-
super::layout();
4904-
asImpl().addNominalTypeDescriptor();
4905-
asImpl().addSuperClass();
4906-
asImpl().addReservedWord();
4907-
asImpl().addReservedWord();
4908-
asImpl().addReservedWord();
4909-
}
4910-
4911-
bool requiresInitializationFunction() {
4912-
// TODO: superclasses?
4913-
return false;
4914-
}
4915-
4916-
CanType getTargetType() const {
4917-
return Target->getDeclaredType()->getCanonicalType();
4918-
}
4919-
};
4920-
49214905
/// An adapter that turns a metadata layout class into a foreign metadata
49224906
/// layout class.
49234907
///
@@ -5034,8 +5018,23 @@ namespace {
50345018
: ForeignMetadataBuilderBase(IGM, target, B) {}
50355019

50365020
void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {
5037-
// TODO: superclasses?
5038-
llvm_unreachable("no supported forms of initialization");
5021+
// Dig out the address of the superclass field.
5022+
auto &layout = IGF.IGM.getForeignMetadataLayout(Target);
5023+
Address metadataWords(IGF.Builder.CreateBitCast(metadata,
5024+
IGM.Int8PtrPtrTy),
5025+
IGM.getPointerAlignment());
5026+
auto superclassField =
5027+
createPointerSizedGEP(IGF, metadataWords,
5028+
layout.getSuperClassOffset().getStaticOffset());
5029+
superclassField =
5030+
IGF.Builder.CreateBitCast(
5031+
superclassField,
5032+
llvm::PointerType::get(IGM.TypeMetadataPtrTy, 0));
5033+
5034+
// Unique the superclass field and write it back.
5035+
auto superclass = IGF.Builder.CreateLoad(superclassField);
5036+
auto uniquedSuperclass = uniqueForeignTypeMetadataRef(IGF, superclass);
5037+
IGF.Builder.CreateStore(uniquedSuperclass, superclassField);
50395038
}
50405039

50415040
// Visitor methods.
@@ -5059,9 +5058,21 @@ namespace {
50595058
B.add(descriptor);
50605059
}
50615060

5061+
void noteStartOfSuperClass() { }
5062+
50625063
void addSuperClass() {
5063-
// TODO: superclasses
5064-
B.addNullPointer(IGM.TypeMetadataPtrTy);
5064+
auto superclassDecl = Target->getSuperclassDecl();
5065+
if (!superclassDecl || !superclassDecl->isForeign()) {
5066+
B.addNullPointer(IGM.TypeMetadataPtrTy);
5067+
return;
5068+
}
5069+
5070+
auto superclassType =
5071+
superclassDecl->swift::TypeDecl::getDeclaredInterfaceType()
5072+
->getCanonicalType();
5073+
auto superclass =
5074+
IGM.getAddrOfForeignTypeMetadataCandidate(superclassType);
5075+
B.add(superclass);
50655076
}
50665077

50675078
void addReservedWord() {

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ namespace irgen {
110110
class EnumMetadataLayout;
111111
class ExplosionSchema;
112112
class FixedTypeInfo;
113+
class ForeignClassMetadataLayout;
113114
class ForeignFunctionInfo;
114115
class FormalType;
115116
class HeapLayout;
@@ -667,10 +668,12 @@ class IRGenModule {
667668

668669
SpareBitVector getSpareBitsForType(llvm::Type *scalarTy, Size size);
669670

670-
NominalMetadataLayout &getMetadataLayout(NominalTypeDecl *decl);
671+
MetadataLayout &getMetadataLayout(NominalTypeDecl *decl);
672+
NominalMetadataLayout &getNominalMetadataLayout(NominalTypeDecl *decl);
671673
StructMetadataLayout &getMetadataLayout(StructDecl *decl);
672-
ClassMetadataLayout &getMetadataLayout(ClassDecl *decl);
674+
ClassMetadataLayout &getClassMetadataLayout(ClassDecl *decl);
673675
EnumMetadataLayout &getMetadataLayout(EnumDecl *decl);
676+
ForeignClassMetadataLayout &getForeignMetadataLayout(ClassDecl *decl);
674677

675678
private:
676679
TypeConverter &Types;

0 commit comments

Comments
 (0)