Skip to content

[Wasm][Runtime] Interpret absolute function pointer in runtime structures #42095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions include/swift/ABI/CompactFunctionPointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===--- CompactFunctionPointer.h - Compact Function Pointers ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift's runtime structures often use relative function pointers to reduce the
// size of metadata and also to minimize load-time overhead in PIC.
// This file defines pointer types whose size and interface are compatible with
// the relative pointer types for targets that do not support relative references
// to code from data.
//===----------------------------------------------------------------------===//

#ifndef SWIFT_ABI_COMPACTFUNCTIONPOINTER_H
#define SWIFT_ABI_COMPACTFUNCTIONPOINTER_H

namespace swift {

/// A compact unconditional absolute function pointer that can fit in a 32-bit
/// integer.
/// As a trade-off compared to relative pointers, this has load-time overhead in PIC
/// and is only available on 32-bit targets.
template <typename T>
class AbsoluteFunctionPointer {
T *Pointer;
static_assert(sizeof(T *) == sizeof(int32_t),
"Function pointer must be 32-bit when using compact absolute pointer");

public:
using PointerTy = T *;

PointerTy get() const & { return Pointer; }

operator PointerTy() const & { return this->get(); }

bool isNull() const & { return Pointer == nullptr; }

/// Resolve a pointer from a `base` pointer and a value loaded from `base`.
template <typename BasePtrTy, typename Value>
static PointerTy resolve(BasePtrTy *base, Value value) {
return reinterpret_cast<PointerTy>(value);
}

template <typename... ArgTy>
typename std::result_of<T *(ArgTy...)>::type operator()(ArgTy... arg) const {
static_assert(std::is_function<T>::value,
"T must be an explicit function type");
return this->get()(std::forward<ArgTy>(arg)...);
}
};

// TODO(katei): Add another pointer structure for 64-bit targets and for efficiency on PIC

} // namespace swift

#endif // SWIFT_ABI_COMPACTFUNCTIONPOINTER_H
2 changes: 1 addition & 1 deletion include/swift/ABI/Executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ template <class AsyncSignature>
class AsyncFunctionPointer {
public:
/// The function to run.
RelativeDirectPointer<AsyncFunctionType<AsyncSignature>,
TargetCompactFunctionPointer<InProcess, AsyncFunctionType<AsyncSignature>,
/*nullable*/ false,
int32_t> Function;

Expand Down
102 changes: 81 additions & 21 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,20 @@ struct TargetMethodDescriptor {
MethodDescriptorFlags Flags;

/// The method implementation.
TargetRelativeDirectPointer<Runtime, void> Impl;
union {
TargetCompactFunctionPointer<Runtime, void> Impl;
TargetRelativeDirectPointer<Runtime, void> AsyncImpl;
};

// TODO: add method types or anything else needed for reflection.

void *getImpl() const {
if (Flags.isAsync()) {
return AsyncImpl.get();
} else {
return Impl.get();
}
}
};

using MethodDescriptor = TargetMethodDescriptor<InProcess>;
Expand Down Expand Up @@ -578,7 +589,20 @@ struct TargetMethodOverrideDescriptor {
TargetRelativeMethodDescriptorPointer<Runtime> Method;

/// The implementation of the override.
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> Impl;
union {
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> Impl;
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> AsyncImpl;
};

void *getImpl() const {
auto *baseMethod = Method.get();
assert(baseMethod && "no base method");
if (baseMethod->Flags.isAsync()) {
return AsyncImpl.get();
} else {
return Impl.get();
}
}
};

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

/// The optional default implementation of the protocol.
RelativeDirectPointer<void, /*nullable*/ true> DefaultImplementation;
union {
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> DefaultFuncImplementation;
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> DefaultImplementation;
};

void *getDefaultImplementation() const {
if (Flags.isFunctionImpl()) {
return DefaultFuncImplementation.get();
} else {
return DefaultImplementation.get();
}
}
};

using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
Expand Down Expand Up @@ -2170,7 +2205,18 @@ using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata<InProcess>;
template <typename Runtime>
struct TargetResilientWitness {
TargetRelativeProtocolRequirementPointer<Runtime> Requirement;
RelativeDirectPointer<void> Witness;
union {
TargetRelativeDirectPointer<Runtime, void> Impl;
TargetCompactFunctionPointer<Runtime, void> FuncImpl;
};

void *getWitness(ProtocolRequirementFlags flags) const {
if (flags.isFunctionImpl()) {
return FuncImpl.get();
} else {
return Impl.get();
}
}
};
using ResilientWitness = TargetResilientWitness<InProcess>;

Expand Down Expand Up @@ -2233,10 +2279,13 @@ struct TargetGenericWitnessTable {
uint16_t WitnessTablePrivateSizeInWordsAndRequiresInstantiation;

/// The instantiation function, which is called after the template is copied.
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
const TargetMetadata<Runtime> *type,
const void * const *instantiationArgs),
/*nullable*/ true> Instantiator;
TargetCompactFunctionPointer<
Runtime,
void(TargetWitnessTable<Runtime> *instantiatedTable,
const TargetMetadata<Runtime> *type,
const void *const *instantiationArgs),
/*nullable*/ true>
Instantiator;

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

Expand Down Expand Up @@ -2968,12 +3017,12 @@ using MetadataCompleter =
template <typename Runtime>
struct TargetGenericMetadataPattern {
/// The function to call to instantiate the template.
TargetRelativeDirectPointer<Runtime, MetadataInstantiator>
TargetCompactFunctionPointer<Runtime, MetadataInstantiator>
InstantiationFunction;

/// The function to call to complete the instantiation. If this is null,
/// the instantiation function must always generate complete metadata.
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
CompletionFunction;

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

/// The heap-destructor function.
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;

/// The ivar-destructor function.
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
IVarDestroyer;

/// The class flags.
Expand Down Expand Up @@ -3284,7 +3333,7 @@ class MetadataAccessFunction {
template <typename Runtime>
struct TargetForeignMetadataInitialization {
/// The completion function. The pattern will always be null.
TargetRelativeDirectPointer<Runtime, MetadataCompleter, /*nullable*/ true>
TargetCompactFunctionPointer<Runtime, MetadataCompleter, /*nullable*/ true>
CompletionFunction;
};

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

/// The heap-destructor function.
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
TargetCompactFunctionPointer<Runtime, HeapObjectDestroyer> Destroy;

/// The ivar-destructor function.
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
TargetCompactFunctionPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
IVarDestroyer;

/// The class flags.
Expand Down Expand Up @@ -3380,7 +3429,7 @@ struct TargetSingletonMetadataInitialization {

/// The completion function. The pattern will always be null, even
/// for a resilient class.
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
TargetCompactFunctionPointer<Runtime, MetadataCompleter>
CompletionFunction;

bool hasResilientClassPattern(
Expand Down Expand Up @@ -3409,7 +3458,7 @@ struct TargetCanonicalSpecializedMetadatasListEntry {

template <typename Runtime>
struct TargetCanonicalSpecializedMetadataAccessorsListEntry {
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false> accessor;
};

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

/// A pointer to the field descriptor for the type, if any.
Expand Down Expand Up @@ -3694,7 +3743,7 @@ class TargetClassDescriptor final
using MetadataListEntry =
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
using MetadataAccessor =
TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
TargetCompactFunctionPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
using MetadataAccessorListEntry =
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>;
using MetadataCachingOnceToken =
Expand Down Expand Up @@ -4495,12 +4544,23 @@ class DynamicReplacementDescriptor {
DynamicReplacementKey *
__ptrauth_swift_dynamic_replacement_key>>
replacedFunctionKey;
RelativeDirectPointer<void, false> replacementFunction;
union {
TargetCompactFunctionPointer<InProcess, void, false> replacementFunction;
TargetRelativeDirectPointer<InProcess, void, false> replacementAsyncFunction;
};
RelativeDirectPointer<DynamicReplacementChainEntry, false> chainEntry;
uint32_t flags;

enum : uint32_t { EnableChainingMask = 0x1 };

void *getReplacementFunction() const {
if (replacedFunctionKey->isAsync()) {
return replacementAsyncFunction.get();
} else {
return replacementFunction.get();
}
}

public:
/// Enable this replacement by changing the function's replacement chain's
/// root entry.
Expand Down
15 changes: 15 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,21 @@ class ProtocolRequirementFlags {

int_type getIntValue() const { return Value; }

/// Is the method implementation is represented as a native function pointer?
bool isFunctionImpl() const {
switch (getKind()) {
case ProtocolRequirementFlags::Kind::Method:
case ProtocolRequirementFlags::Kind::Init:
case ProtocolRequirementFlags::Kind::Getter:
case ProtocolRequirementFlags::Kind::Setter:
case ProtocolRequirementFlags::Kind::ReadCoroutine:
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
return !isAsync();
default:
return false;
}
}

enum : uintptr_t {
/// Bit used to indicate that an associated type witness is a pointer to
/// a mangled name (vs. a pointer to metadata).
Expand Down
18 changes: 18 additions & 0 deletions include/swift/ABI/TargetLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "swift/Runtime/Config.h"
#include "swift/Basic/RelativePointer.h"
#include "swift/ABI/CompactFunctionPointer.h"

namespace swift {

Expand Down Expand Up @@ -101,6 +102,14 @@ struct InProcess {
template <typename T, bool Nullable = true>
using RelativeDirectPointer = RelativeDirectPointer<T, Nullable>;

template <typename T, bool Nullable = true, typename Offset = int32_t>
#if SWIFT_COMPACT_ABSOLUTE_FUNCTION_POINTER
using CompactFunctionPointer = AbsoluteFunctionPointer<T>;
#else
using CompactFunctionPointer =
swift::RelativeDirectPointer<T, Nullable, Offset>;
#endif

template<typename T>
T *getStrippedSignedPointer(const T *pointer) const {
return swift_ptrauth_strip(pointer);
Expand Down Expand Up @@ -163,6 +172,9 @@ struct External {
template <typename T, bool Nullable = true>
using RelativeDirectPointer = int32_t;

template <typename T, bool Nullable = true, typename Offset = int32_t>
using CompactFunctionPointer = int32_t;

StoredPointer getStrippedSignedPointer(const StoredSignedPointer pointer) const {
return swift_ptrauth_strip(pointer);
}
Expand Down Expand Up @@ -191,6 +203,12 @@ template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeIndirectablePointer
= typename Runtime::template RelativeIndirectablePointer<Pointee,Nullable>;

template <typename Runtime, typename Pointee, bool Nullable = true,
typename Offset = int32_t>
using TargetCompactFunctionPointer =
typename Runtime::template CompactFunctionPointer<Pointee, Nullable,
Offset>;

} // end namespace swift

#endif
Loading