Skip to content

Commit f492250

Browse files
Merge pull request #42095 from kateinoigakukun/pr-26594e2245d681b594f6e1b190c8107a1c6dbb1d
[Wasm][Runtime] Interpret absolute function pointer in runtime structures
2 parents 62a2c9e + 8c598e9 commit f492250

File tree

13 files changed

+251
-44
lines changed

13 files changed

+251
-44
lines changed
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/Metadata.h

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

508508
/// The method implementation.
509-
TargetRelativeDirectPointer<Runtime, void> Impl;
509+
union {
510+
TargetCompactFunctionPointer<Runtime, void> Impl;
511+
TargetRelativeDirectPointer<Runtime, void> AsyncImpl;
512+
};
510513

511514
// TODO: add method types or anything else needed for reflection.
515+
516+
void *getImpl() const {
517+
if (Flags.isAsync()) {
518+
return AsyncImpl.get();
519+
} else {
520+
return Impl.get();
521+
}
522+
}
512523
};
513524

514525
using MethodDescriptor = TargetMethodDescriptor<InProcess>;
@@ -578,7 +589,20 @@ struct TargetMethodOverrideDescriptor {
578589
TargetRelativeMethodDescriptorPointer<Runtime> Method;
579590

580591
/// The implementation of the override.
581-
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> Impl;
592+
union {
593+
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> Impl;
594+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> AsyncImpl;
595+
};
596+
597+
void *getImpl() const {
598+
auto *baseMethod = Method.get();
599+
assert(baseMethod && "no base method");
600+
if (baseMethod->Flags.isAsync()) {
601+
return AsyncImpl.get();
602+
} else {
603+
return Impl.get();
604+
}
605+
}
582606
};
583607

584608
/// Header for a class vtable override descriptor. This is a variable-sized
@@ -1523,7 +1547,18 @@ struct TargetProtocolRequirement {
15231547
// TODO: name, type
15241548

15251549
/// The optional default implementation of the protocol.
1526-
RelativeDirectPointer<void, /*nullable*/ true> DefaultImplementation;
1550+
union {
1551+
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> DefaultFuncImplementation;
1552+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> DefaultImplementation;
1553+
};
1554+
1555+
void *getDefaultImplementation() const {
1556+
if (Flags.isFunctionImpl()) {
1557+
return DefaultFuncImplementation.get();
1558+
} else {
1559+
return DefaultImplementation.get();
1560+
}
1561+
}
15271562
};
15281563

15291564
using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
@@ -2170,7 +2205,18 @@ using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata<InProcess>;
21702205
template <typename Runtime>
21712206
struct TargetResilientWitness {
21722207
TargetRelativeProtocolRequirementPointer<Runtime> Requirement;
2173-
RelativeDirectPointer<void> Witness;
2208+
union {
2209+
TargetRelativeDirectPointer<Runtime, void> Impl;
2210+
TargetCompactFunctionPointer<Runtime, void> FuncImpl;
2211+
};
2212+
2213+
void *getWitness(ProtocolRequirementFlags flags) const {
2214+
if (flags.isFunctionImpl()) {
2215+
return FuncImpl.get();
2216+
} else {
2217+
return Impl.get();
2218+
}
2219+
}
21742220
};
21752221
using ResilientWitness = TargetResilientWitness<InProcess>;
21762222

@@ -2233,10 +2279,13 @@ struct TargetGenericWitnessTable {
22332279
uint16_t WitnessTablePrivateSizeInWordsAndRequiresInstantiation;
22342280

22352281
/// The instantiation function, which is called after the template is copied.
2236-
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
2237-
const TargetMetadata<Runtime> *type,
2238-
const void * const *instantiationArgs),
2239-
/*nullable*/ true> Instantiator;
2282+
TargetCompactFunctionPointer<
2283+
Runtime,
2284+
void(TargetWitnessTable<Runtime> *instantiatedTable,
2285+
const TargetMetadata<Runtime> *type,
2286+
const void *const *instantiationArgs),
2287+
/*nullable*/ true>
2288+
Instantiator;
22402289

22412290
using PrivateDataType = void *[swift::NumGenericMetadataPrivateDataWords];
22422291

@@ -2968,12 +3017,12 @@ using MetadataCompleter =
29683017
template <typename Runtime>
29693018
struct TargetGenericMetadataPattern {
29703019
/// The function to call to instantiate the template.
2971-
TargetRelativeDirectPointer<Runtime, MetadataInstantiator>
3020+
TargetCompactFunctionPointer<Runtime, MetadataInstantiator>
29723021
InstantiationFunction;
29733022

29743023
/// The function to call to complete the instantiation. If this is null,
29753024
/// the instantiation function must always generate complete metadata.
2976-
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
3025+
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
29773026
CompletionFunction;
29783027

29793028
/// Flags describing the layout of this instantiation pattern.
@@ -3080,10 +3129,10 @@ struct TargetGenericClassMetadataPattern final :
30803129
using TargetGenericMetadataPattern<Runtime>::PatternFlags;
30813130

30823131
/// The heap-destructor function.
3083-
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
3132+
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;
30843133

30853134
/// The ivar-destructor function.
3086-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
3135+
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
30873136
IVarDestroyer;
30883137

30893138
/// The class flags.
@@ -3284,7 +3333,7 @@ class MetadataAccessFunction {
32843333
template <typename Runtime>
32853334
struct TargetForeignMetadataInitialization {
32863335
/// The completion function. The pattern will always be null.
3287-
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
3336+
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
32883337
CompletionFunction;
32893338
};
32903339

@@ -3329,14 +3378,14 @@ struct TargetResilientClassMetadataPattern {
33293378
///
33303379
/// If this is null, the runtime instead calls swift_relocateClassMetadata(),
33313380
/// passing in the class descriptor and this pattern.
3332-
TargetRelativeDirectPointer<Runtime, MetadataRelocator, /*nullable*/ true>
3381+
TargetCompactFunctionPointer<Runtime, MetadataRelocator, /*nullable*/ true>
33333382
RelocationFunction;
33343383

33353384
/// The heap-destructor function.
3336-
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
3385+
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;
33373386

33383387
/// The ivar-destructor function.
3339-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
3388+
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
33403389
IVarDestroyer;
33413390

33423391
/// The class flags.
@@ -3380,7 +3429,7 @@ struct TargetSingletonMetadataInitialization {
33803429

33813430
/// The completion function. The pattern will always be null, even
33823431
/// for a resilient class.
3383-
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
3432+
TargetCompactFunctionPointer<Runtime, MetadataCompleter>
33843433
CompletionFunction;
33853434

33863435
bool hasResilientClassPattern(
@@ -3409,7 +3458,7 @@ struct TargetCanonicalSpecializedMetadatasListEntry {
34093458

34103459
template <typename Runtime>
34113460
struct TargetCanonicalSpecializedMetadataAccessorsListEntry {
3412-
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
3461+
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
34133462
};
34143463

34153464
template <typename Runtime>
@@ -3429,7 +3478,7 @@ class TargetTypeContextDescriptor
34293478
/// The function type here is a stand-in. You should use getAccessFunction()
34303479
/// to wrap the function pointer in an accessor that uses the proper calling
34313480
/// convention for a given number of arguments.
3432-
TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
3481+
TargetCompactFunctionPointer<Runtime, MetadataResponse(...),
34333482
/*Nullable*/ true> AccessFunctionPtr;
34343483

34353484
/// A pointer to the field descriptor for the type, if any.
@@ -3694,7 +3743,7 @@ class TargetClassDescriptor final
36943743
using MetadataListEntry =
36953744
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
36963745
using MetadataAccessor =
3697-
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
3746+
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
36983747
using MetadataAccessorListEntry =
36993748
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>;
37003749
using MetadataCachingOnceToken =
@@ -4495,12 +4544,23 @@ class DynamicReplacementDescriptor {
44954544
DynamicReplacementKey *
44964545
__ptrauth_swift_dynamic_replacement_key>>
44974546
replacedFunctionKey;
4498-
RelativeDirectPointer<void, false> replacementFunction;
4547+
union {
4548+
TargetCompactFunctionPointer<InProcess, void, false> replacementFunction;
4549+
TargetRelativeDirectPointer<InProcess, void, false> replacementAsyncFunction;
4550+
};
44994551
RelativeDirectPointer<DynamicReplacementChainEntry, false> chainEntry;
45004552
uint32_t flags;
45014553

45024554
enum : uint32_t { EnableChainingMask = 0x1 };
45034555

4556+
void *getReplacementFunction() const {
4557+
if (replacedFunctionKey->isAsync()) {
4558+
return replacementAsyncFunction.get();
4559+
} else {
4560+
return replacementFunction.get();
4561+
}
4562+
}
4563+
45044564
public:
45054565
/// Enable this replacement by changing the function's replacement chain's
45064566
/// root entry.

include/swift/ABI/MetadataValues.h

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

612612
int_type getIntValue() const { return Value; }
613613

614+
/// Is the method implementation is represented as a native function pointer?
615+
bool isFunctionImpl() const {
616+
switch (getKind()) {
617+
case ProtocolRequirementFlags::Kind::Method:
618+
case ProtocolRequirementFlags::Kind::Init:
619+
case ProtocolRequirementFlags::Kind::Getter:
620+
case ProtocolRequirementFlags::Kind::Setter:
621+
case ProtocolRequirementFlags::Kind::ReadCoroutine:
622+
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
623+
return !isAsync();
624+
default:
625+
return false;
626+
}
627+
}
628+
614629
enum : uintptr_t {
615630
/// Bit used to indicate that an associated type witness is a pointer to
616631
/// 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

@@ -101,6 +102,14 @@ struct InProcess {
101102
template <typename T, bool Nullable = true>
102103
using RelativeDirectPointer = RelativeDirectPointer<T, Nullable>;
103104

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
112+
104113
template<typename T>
105114
T *getStrippedSignedPointer(const T *pointer) const {
106115
return swift_ptrauth_strip(pointer);
@@ -163,6 +172,9 @@ struct External {
163172
template <typename T, bool Nullable = true>
164173
using RelativeDirectPointer = int32_t;
165174

175+
template <typename T, bool Nullable = true, typename Offset = int32_t>
176+
using CompactFunctionPointer = int32_t;
177+
166178
StoredPointer getStrippedSignedPointer(const StoredSignedPointer pointer) const {
167179
return swift_ptrauth_strip(pointer);
168180
}
@@ -191,6 +203,12 @@ template <typename Runtime, typename Pointee, bool Nullable = true>
191203
using TargetRelativeIndirectablePointer
192204
= typename Runtime::template RelativeIndirectablePointer<Pointee,Nullable>;
193205

206+
template <typename Runtime, typename Pointee, bool Nullable = true,
207+
typename Offset = int32_t>
208+
using TargetCompactFunctionPointer =
209+
typename Runtime::template CompactFunctionPointer<Pointee, Nullable,
210+
Offset>;
211+
194212
} // end namespace swift
195213

196214
#endif

0 commit comments

Comments
 (0)