Skip to content

Commit b9f6454

Browse files
committed
[embedded] Add support for storing/casting function types
1 parent 16206fa commit b9f6454

File tree

8 files changed

+133
-4
lines changed

8 files changed

+133
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,8 @@ func isCastSupportedInEmbeddedSwift(from sourceType: Type,
10101010
return false
10111011
}
10121012

1013-
if !destType.isStruct && !destType.isClass && !destType.isEnum && !destType.isTuple {
1013+
if !destType.isStruct && !destType.isClass && !destType.isEnum &&
1014+
!destType.isTuple && !destType.isLoweredFunction {
10141015
return false
10151016
}
10161017

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- FunctionMetadataVisitor.h - CRTP for function metadata -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 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 function metadata.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_IRGEN_FUNCTIONMETADATALAYOUT_H
18+
#define SWIFT_IRGEN_FUNCTIONMETADATALAYOUT_H
19+
20+
21+
namespace swift {
22+
namespace irgen {
23+
24+
/// A CRTP class for laying out function metadata.
25+
///
26+
/// This produces an object corresponding to a FunctionTypeMetadata type.
27+
/// It does not itself doing anything special for metadata templates.
28+
template <class Impl> struct FunctionMetadataVisitor
29+
: public MetadataVisitor<Impl> {
30+
using super = MetadataVisitor<Impl>;
31+
32+
protected:
33+
using super::asImpl;
34+
35+
FunctionType *const Target;
36+
37+
FunctionMetadataVisitor(IRGenModule &IGM, FunctionType *const target)
38+
: super(IGM), Target(target) {}
39+
40+
public:
41+
42+
void embeddedLayout() {
43+
// The embedded layout consists of:
44+
// -1 : vwt
45+
// 0 : metadata flags
46+
super::layout();
47+
}
48+
};
49+
50+
} // end namespace irgen
51+
} // end namespace swift
52+
53+
#endif

lib/IRGen/GenDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5480,7 +5480,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
54805480
}
54815481

54825482
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
5483-
isa<TupleType>(concreteType)) {
5483+
(isa<TupleType>(concreteType) ||
5484+
isa<FunctionType>(concreteType))) {
54845485
IRGen.noteUseOfSpecializedValueMetadata(concreteType);
54855486
}
54865487

lib/IRGen/GenMeta.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#include "StructLayout.h"
7777
#include "StructMetadataVisitor.h"
7878
#include "TupleMetadataVisitor.h"
79+
#include "FunctionMetadataVisitor.h"
7980

8081
#include "GenMeta.h"
8182

@@ -5615,6 +5616,8 @@ void irgen::emitLazySpecializedValueMetadata(IRGenModule &IGM,
56155616

56165617
if (isa<TupleType>(valueTy)) {
56175618
emitLazyTupleMetadata(IGM, valueTy);
5619+
} else if (isa<FunctionType>(valueTy)) {
5620+
emitLazyFunctionMetadata(IGM, valueTy);
56185621
} else if (valueTy->getStructOrBoundGenericStruct()) {
56195622
emitSpecializedGenericStructMetadata(IGM, valueTy,
56205623
*valueTy.getStructOrBoundGenericStruct());
@@ -6327,6 +6330,66 @@ void irgen::emitLazyTupleMetadata(IRGenModule &IGM, CanType tupleTy) {
63276330
IGM.defineTypeMetadata(tupleTy, isPattern, canBeConstant,
63286331
init.finishAndCreateFuture());
63296332
}
6333+
6334+
// Functions (only used in embedded existentials mode)
6335+
//
6336+
namespace {
6337+
class FunctionMetadataBuilder : public FunctionMetadataVisitor<FunctionMetadataBuilder> {
6338+
using super = FunctionMetadataVisitor<FunctionMetadataBuilder>;
6339+
6340+
ConstantStructBuilder &B;
6341+
6342+
protected:
6343+
6344+
using super::asImpl;
6345+
using super::IGM;
6346+
using super::Target;
6347+
6348+
public:
6349+
FunctionMetadataBuilder(IRGenModule &IGM, CanType funTy, ConstantStructBuilder &B) :
6350+
super(IGM, cast<FunctionType>(funTy)), B(B) {}
6351+
6352+
ConstantReference emitValueWitnessTable(bool relativeReference) {
6353+
return irgen::emitValueWitnessTable(IGM, Target->getCanonicalType(),
6354+
false, relativeReference);
6355+
}
6356+
6357+
void addMetadataFlags() {
6358+
B.addInt(IGM.MetadataKindTy, unsigned(MetadataKind::Function));
6359+
}
6360+
6361+
void addValueWitnessTable() {
6362+
auto vwtPointer = emitValueWitnessTable(false).getValue();
6363+
B.addSignedPointer(vwtPointer,
6364+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6365+
PointerAuthEntity());
6366+
}
6367+
};
6368+
} // end anonymous namespace
6369+
6370+
void irgen::emitLazyFunctionMetadata(IRGenModule &IGM, CanType funTy) {
6371+
assert(IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials));
6372+
assert(isa<FunctionType>(funTy));
6373+
6374+
Type ty = funTy.getPointer();
6375+
auto &context = ty->getASTContext();
6376+
PrettyStackTraceType stackTraceRAII(
6377+
context, "emitting prespecialized metadata for", ty);
6378+
6379+
ConstantInitBuilder initBuilder(IGM);
6380+
auto init = initBuilder.beginStruct();
6381+
init.setPacked(true);
6382+
6383+
bool isPattern = false;
6384+
bool canBeConstant = true;
6385+
6386+
FunctionMetadataBuilder builder(IGM, funTy, init);
6387+
builder.embeddedLayout();
6388+
6389+
IGM.defineTypeMetadata(funTy, isPattern, canBeConstant,
6390+
init.finishAndCreateFuture());
6391+
6392+
}
63306393
// Enums
63316394

63326395
static std::optional<Size>

lib/IRGen/GenMeta.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ namespace irgen {
114114
/// Emit the metadata associated with a given tuple type.
115115
void emitLazyTupleMetadata(IRGenModule &IGM, CanType type);
116116

117+
/// Emit the metadata associated with a given function type.
118+
void emitLazyFunctionMetadata(IRGenModule &IGM, CanType funTy);
119+
117120
/// Emit the metadata associated with a given instantiation of a generic
118121
// class.
119122
void emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,

lib/IRGen/Linking.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,8 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
698698

699699
// In embedded existenitals mode we generate metadata for tuple types.
700700
if (getType()->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
701-
isa<TupleType>(getType())) {
701+
(isa<TupleType>(getType()) ||
702+
isa<FunctionType>(getType()))) {
702703
return SILLinkage::Shared;
703704
}
704705

lib/IRGen/MetadataRequest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,9 @@ static CanPackType getInducedPackType(AnyFunctionType::CanParamArrayRef params,
15681568
static MetadataResponse emitFunctionTypeMetadataRef(IRGenFunction &IGF,
15691569
CanFunctionType type,
15701570
DynamicMetadataRequest request) {
1571+
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
1572+
return MetadataResponse::forComplete(IGF.IGM.getAddrOfTypeMetadata(type));
1573+
}
15711574
auto result =
15721575
IGF.emitAbstractTypeMetadataRef(type->getResult()->getCanonicalType());
15731576

test/embedded/existential.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ enum GenericEnumWithClass<T> {
6262
// OUTPUT: deinit called
6363
// OUTPUT: deinit called
6464
// OUTPUT: deinit called
65-
6665
// OUTPUT-NOT: deinit called
66+
// OUTPUT: hello world
6767

6868
func test() {
6969
let _: any Any = GC<Int>()
@@ -76,6 +76,10 @@ func test() {
7676
let _: any Any = (StructWithClass(), StructWithClass())
7777
// outline storage case
7878
let _: any Any = (StructWithClass(), StructWithClass(), StructWithClass(), StructWithClass())
79+
let c: any Any = { print("hello world") }
80+
if let cl = c as? () -> () {
81+
cl()
82+
}
7983
}
8084

8185
protocol Basic {

0 commit comments

Comments
 (0)