Skip to content

Commit d5463cf

Browse files
Merge pull request #4389 from swiftwasm/katei/move-to-unconditional-absfuncptr
2 parents 2b3a974 + 72c9e34 commit d5463cf

29 files changed

+406
-183
lines changed

cmake/caches/Runtime-WASI-wasm32.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ set(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME TRUE CACHE BOOL "")
3131

3232
set(SWIFT_STDLIB_SUPPORTS_BACKTRACE_REPORTING FALSE CACHE BOOL "")
3333
set(SWIFT_STDLIB_HAS_DLADDR FALSE CACHE BOOL "")
34+
set(SWIFT_STDLIB_COMPACT_ABSOLUTE_FUNCTION_POINTER TRUE CACHE BOOL "")
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===--- CompactFunctionPointer.h - Compact Function Pointers ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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+
// Swift's runtime structures often use relative function pointers to reduce the
14+
// size of metadata and also to minimize load-time overhead in PIC.
15+
// This file defines pointer types whose size and interface are compatible with
16+
// the relative pointer types for targets that do not support relative references
17+
// to code from data.
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef SWIFT_ABI_COMPACTFUNCTIONPOINTER_H
21+
#define SWIFT_ABI_COMPACTFUNCTIONPOINTER_H
22+
23+
namespace swift {
24+
25+
/// A compact unconditional absolute function pointer that can fit in a 32-bit
26+
/// integer.
27+
/// As a trade-off compared to relative pointers, this has load-time overhead in PIC
28+
/// and is only available on 32-bit targets.
29+
template <typename T>
30+
class AbsoluteFunctionPointer {
31+
T *Pointer;
32+
static_assert(sizeof(T *) == sizeof(int32_t),
33+
"Function pointer must be 32-bit when using compact absolute pointer");
34+
35+
public:
36+
using PointerTy = T *;
37+
38+
PointerTy get() const & { return Pointer; }
39+
40+
operator PointerTy() const & { return this->get(); }
41+
42+
bool isNull() const & { return Pointer == nullptr; }
43+
44+
/// Resolve a pointer from a `base` pointer and a value loaded from `base`.
45+
template <typename BasePtrTy, typename Value>
46+
static PointerTy resolve(BasePtrTy *base, Value value) {
47+
return reinterpret_cast<PointerTy>(value);
48+
}
49+
50+
template <typename... ArgTy>
51+
typename std::result_of<T *(ArgTy...)>::type operator()(ArgTy... arg) const {
52+
static_assert(std::is_function<T>::value,
53+
"T must be an explicit function type");
54+
return this->get()(std::forward<ArgTy>(arg)...);
55+
}
56+
};
57+
58+
// TODO(katei): Add another pointer structure for 64-bit targets and for efficiency on PIC
59+
60+
} // namespace swift
61+
62+
#endif // SWIFT_ABI_COMPACTFUNCTIONPOINTER_H

include/swift/ABI/Executor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ template <class AsyncSignature>
241241
class AsyncFunctionPointer {
242242
public:
243243
/// The function to run.
244-
RelativeDirectPointer<AsyncFunctionType<AsyncSignature>,
244+
TargetCompactFunctionPointer<InProcess, AsyncFunctionType<AsyncSignature>,
245245
/*nullable*/ false,
246246
int32_t> Function;
247247

include/swift/ABI/KeyPath.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ class KeyPathComponentHeader {
192192

193193
enum ComputedPropertyIDResolution {
194194
Resolved,
195+
ResolvedAbsolute,
195196
IndirectPointer,
196197
FunctionCall,
197198
};
@@ -214,6 +215,7 @@ class KeyPathComponentHeader {
214215
? _SwiftKeyPathComponentHeader_ComputedIDByVTableOffsetFlag : 0)
215216
| (hasArguments ? _SwiftKeyPathComponentHeader_ComputedHasArgumentsFlag : 0)
216217
| (resolution == Resolved ? _SwiftKeyPathComponentHeader_ComputedIDResolved
218+
: resolution == ResolvedAbsolute ? _SwiftKeyPathComponentHeader_ComputedIDResolvedAbsolute
217219
: resolution == IndirectPointer ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer
218220
: resolution == FunctionCall ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFunctionCall
219221
: (assert(false && "invalid resolution"), 0)));

include/swift/ABI/Metadata.h

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,20 @@ struct TargetMethodDescriptor {
502502
MethodDescriptorFlags Flags;
503503

504504
/// The method implementation.
505-
TargetRelativeDirectPointer<Runtime, void> Impl;
505+
union {
506+
TargetCompactFunctionPointer<Runtime, void> Impl;
507+
TargetRelativeDirectPointer<Runtime, void> AsyncImpl;
508+
};
506509

507510
// TODO: add method types or anything else needed for reflection.
511+
512+
void *getImpl() const {
513+
if (Flags.isAsync()) {
514+
return AsyncImpl.get();
515+
} else {
516+
return Impl.get();
517+
}
518+
}
508519
};
509520

510521
using MethodDescriptor = TargetMethodDescriptor<InProcess>;
@@ -574,7 +585,20 @@ struct TargetMethodOverrideDescriptor {
574585
TargetRelativeMethodDescriptorPointer<Runtime> Method;
575586

576587
/// The implementation of the override.
577-
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> Impl;
588+
union {
589+
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> Impl;
590+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> AsyncImpl;
591+
};
592+
593+
void *getImpl() const {
594+
auto *baseMethod = Method.get();
595+
assert(baseMethod && "no base method");
596+
if (baseMethod->Flags.isAsync()) {
597+
return AsyncImpl.get();
598+
} else {
599+
return Impl.get();
600+
}
601+
}
578602
};
579603

580604
/// Header for a class vtable override descriptor. This is a variable-sized
@@ -1519,7 +1543,18 @@ struct TargetProtocolRequirement {
15191543
// TODO: name, type
15201544

15211545
/// The optional default implementation of the protocol.
1522-
RelativeDirectPointer<void, /*nullable*/ true> DefaultImplementation;
1546+
union {
1547+
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> DefaultFuncImplementation;
1548+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> DefaultImplementation;
1549+
};
1550+
1551+
void *getDefaultImplementation() const {
1552+
if (Flags.isFunctionImpl()) {
1553+
return DefaultFuncImplementation.get();
1554+
} else {
1555+
return DefaultImplementation.get();
1556+
}
1557+
}
15231558
};
15241559

15251560
using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
@@ -1808,7 +1843,18 @@ using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata<InProcess>;
18081843
template <typename Runtime>
18091844
struct TargetResilientWitness {
18101845
TargetRelativeProtocolRequirementPointer<Runtime> Requirement;
1811-
RelativeDirectPointer<void> Witness;
1846+
union {
1847+
TargetRelativeDirectPointer<Runtime, void> Impl;
1848+
TargetCompactFunctionPointer<Runtime, void> FuncImpl;
1849+
};
1850+
1851+
void *getWitness(ProtocolRequirementFlags flags) const {
1852+
if (flags.isFunctionImpl()) {
1853+
return FuncImpl.get();
1854+
} else {
1855+
return Impl.get();
1856+
}
1857+
}
18121858
};
18131859
using ResilientWitness = TargetResilientWitness<InProcess>;
18141860

@@ -1871,10 +1917,13 @@ struct TargetGenericWitnessTable {
18711917
uint16_t WitnessTablePrivateSizeInWordsAndRequiresInstantiation;
18721918

18731919
/// The instantiation function, which is called after the template is copied.
1874-
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
1875-
const TargetMetadata<Runtime> *type,
1876-
const void * const *instantiationArgs),
1877-
/*nullable*/ true> Instantiator;
1920+
TargetCompactFunctionPointer<
1921+
Runtime,
1922+
void(TargetWitnessTable<Runtime> *instantiatedTable,
1923+
const TargetMetadata<Runtime> *type,
1924+
const void *const *instantiationArgs),
1925+
/*nullable*/ true>
1926+
Instantiator;
18781927

18791928
using PrivateDataType = void *[swift::NumGenericMetadataPrivateDataWords];
18801929

@@ -2606,12 +2655,12 @@ using MetadataCompleter =
26062655
template <typename Runtime>
26072656
struct TargetGenericMetadataPattern {
26082657
/// The function to call to instantiate the template.
2609-
TargetRelativeDirectPointer<Runtime, MetadataInstantiator>
2658+
TargetCompactFunctionPointer<Runtime, MetadataInstantiator>
26102659
InstantiationFunction;
26112660

26122661
/// The function to call to complete the instantiation. If this is null,
26132662
/// the instantiation function must always generate complete metadata.
2614-
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
2663+
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
26152664
CompletionFunction;
26162665

26172666
/// Flags describing the layout of this instantiation pattern.
@@ -2718,10 +2767,10 @@ struct TargetGenericClassMetadataPattern final :
27182767
using TargetGenericMetadataPattern<Runtime>::PatternFlags;
27192768

27202769
/// The heap-destructor function.
2721-
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
2770+
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;
27222771

27232772
/// The ivar-destructor function.
2724-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
2773+
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
27252774
IVarDestroyer;
27262775

27272776
/// The class flags.
@@ -2922,7 +2971,7 @@ class MetadataAccessFunction {
29222971
template <typename Runtime>
29232972
struct TargetForeignMetadataInitialization {
29242973
/// The completion function. The pattern will always be null.
2925-
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
2974+
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
29262975
CompletionFunction;
29272976
};
29282977

@@ -2967,14 +3016,14 @@ struct TargetResilientClassMetadataPattern {
29673016
///
29683017
/// If this is null, the runtime instead calls swift_relocateClassMetadata(),
29693018
/// passing in the class descriptor and this pattern.
2970-
TargetRelativeDirectPointer<Runtime, MetadataRelocator, /*nullable*/ true>
3019+
TargetCompactFunctionPointer<Runtime, MetadataRelocator, /*nullable*/ true>
29713020
RelocationFunction;
29723021

29733022
/// The heap-destructor function.
2974-
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
3023+
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;
29753024

29763025
/// The ivar-destructor function.
2977-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
3026+
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
29783027
IVarDestroyer;
29793028

29803029
/// The class flags.
@@ -3018,7 +3067,7 @@ struct TargetSingletonMetadataInitialization {
30183067

30193068
/// The completion function. The pattern will always be null, even
30203069
/// for a resilient class.
3021-
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
3070+
TargetCompactFunctionPointer<Runtime, MetadataCompleter>
30223071
CompletionFunction;
30233072

30243073
bool hasResilientClassPattern(
@@ -3047,7 +3096,7 @@ struct TargetCanonicalSpecializedMetadatasListEntry {
30473096

30483097
template <typename Runtime>
30493098
struct TargetCanonicalSpecializedMetadataAccessorsListEntry {
3050-
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
3099+
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
30513100
};
30523101

30533102
template <typename Runtime>
@@ -3067,7 +3116,7 @@ class TargetTypeContextDescriptor
30673116
/// The function type here is a stand-in. You should use getAccessFunction()
30683117
/// to wrap the function pointer in an accessor that uses the proper calling
30693118
/// convention for a given number of arguments.
3070-
TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
3119+
TargetCompactFunctionPointer<Runtime, MetadataResponse(...),
30713120
/*Nullable*/ true> AccessFunctionPtr;
30723121

30733122
/// A pointer to the field descriptor for the type, if any.
@@ -3332,7 +3381,7 @@ class TargetClassDescriptor final
33323381
using MetadataListEntry =
33333382
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
33343383
using MetadataAccessor =
3335-
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
3384+
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
33363385
using MetadataAccessorListEntry =
33373386
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>;
33383387
using MetadataCachingOnceToken =
@@ -4133,12 +4182,23 @@ class DynamicReplacementDescriptor {
41334182
DynamicReplacementKey *
41344183
__ptrauth_swift_dynamic_replacement_key>>
41354184
replacedFunctionKey;
4136-
RelativeDirectPointer<void, false> replacementFunction;
4185+
union {
4186+
TargetCompactFunctionPointer<InProcess, void, false> replacementFunction;
4187+
TargetRelativeDirectPointer<InProcess, void, false> replacementAsyncFunction;
4188+
};
41374189
RelativeDirectPointer<DynamicReplacementChainEntry, false> chainEntry;
41384190
uint32_t flags;
41394191

41404192
enum : uint32_t { EnableChainingMask = 0x1 };
41414193

4194+
void *getReplacementFunction() const {
4195+
if (replacedFunctionKey->isAsync()) {
4196+
return replacementAsyncFunction.get();
4197+
} else {
4198+
return replacementFunction.get();
4199+
}
4200+
}
4201+
41424202
public:
41434203
/// Enable this replacement by changing the function's replacement chain's
41444204
/// root entry.

include/swift/ABI/MetadataValues.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,21 @@ class ProtocolRequirementFlags {
603603

604604
int_type getIntValue() const { return Value; }
605605

606+
/// Is the method implementation is represented as a native function pointer?
607+
bool isFunctionImpl() const {
608+
switch (getKind()) {
609+
case ProtocolRequirementFlags::Kind::Method:
610+
case ProtocolRequirementFlags::Kind::Init:
611+
case ProtocolRequirementFlags::Kind::Getter:
612+
case ProtocolRequirementFlags::Kind::Setter:
613+
case ProtocolRequirementFlags::Kind::ReadCoroutine:
614+
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
615+
return !isAsync();
616+
default:
617+
return false;
618+
}
619+
}
620+
606621
enum : uintptr_t {
607622
/// Bit used to indicate that an associated type witness is a pointer to
608623
/// a mangled name (vs. a pointer to metadata).

include/swift/ABI/TargetLayout.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "swift/Runtime/Config.h"
3333
#include "swift/Basic/RelativePointer.h"
34+
#include "swift/ABI/CompactFunctionPointer.h"
3435

3536
namespace swift {
3637

@@ -100,6 +101,14 @@ struct InProcess {
100101

101102
template <typename T, bool Nullable = true>
102103
using RelativeDirectPointer = RelativeDirectPointer<T, Nullable>;
104+
105+
template <typename T, bool Nullable = true, typename Offset = int32_t>
106+
#if SWIFT_COMPACT_ABSOLUTE_FUNCTION_POINTER
107+
using CompactFunctionPointer = AbsoluteFunctionPointer<T>;
108+
#else
109+
using CompactFunctionPointer =
110+
swift::RelativeDirectPointer<T, Nullable, Offset>;
111+
#endif
103112
};
104113

105114
/// Represents a pointer in another address space.
@@ -157,6 +166,9 @@ struct External {
157166

158167
template <typename T, bool Nullable = true>
159168
using RelativeDirectPointer = int32_t;
169+
170+
template <typename T, bool Nullable = true, typename Offset = int32_t>
171+
using CompactFunctionPointer = int32_t;
160172
};
161173

162174
template <typename Runtime, typename T>
@@ -182,6 +194,12 @@ template <typename Runtime, typename Pointee, bool Nullable = true>
182194
using TargetRelativeIndirectablePointer
183195
= typename Runtime::template RelativeIndirectablePointer<Pointee,Nullable>;
184196

197+
template <typename Runtime, typename Pointee, bool Nullable = true,
198+
typename Offset = int32_t>
199+
using TargetCompactFunctionPointer =
200+
typename Runtime::template CompactFunctionPointer<Pointee, Nullable,
201+
Offset>;
202+
185203
} // end namespace swift
186204

187205
#endif

include/swift/AST/IRGenOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ class IRGenOptions {
320320
unsigned LazyInitializeProtocolConformances : 1;
321321
unsigned IndirectAsyncFunctionPointer : 1;
322322

323+
/// Use absolute function references instead of relative ones.
324+
/// Mainly used on WebAssembly, that doesn't support relative references
325+
/// to code from data.
326+
unsigned CompactAbsoluteFunctionPointer : 1;
327+
323328
/// Normally if the -read-legacy-type-info flag is not specified, we look for
324329
/// a file named "legacy-<arch>.yaml" in SearchPathOpts.RuntimeLibraryPath.
325330
/// Passing this flag completely disables this behavior.

0 commit comments

Comments
 (0)