Skip to content
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

[Distributed] Implement distributed method accessors #40270

Merged
merged 38 commits into from
Dec 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4860f90
[SIL] Add new flag to `SILFunction` - `IsDistributed`
xedin Nov 17, 2021
b8358b2
[Mangling] Add mangling for distributed method accessors
xedin Nov 19, 2021
9ebdf36
[IRGen] Add skeleton implementation of distributed method accessor
xedin Nov 19, 2021
19bf160
[Distributed] IRGen: Add argument loading from `UnsafeRawPointer` int…
xedin Nov 22, 2021
ac2973d
[Distributed] IRGen: Form a callee for a distributed method
xedin Nov 23, 2021
a866a7a
[Distributed] IRGen: Emit a call to a distributed method
xedin Nov 23, 2021
185a663
[Distributed] IRGen: Forward distributed method results through accessor
xedin Nov 23, 2021
2179db3
[IRGen] Linking: Make it possible to form async pointers to distribut…
xedin Nov 24, 2021
9d1c103
[Distributed] IRGen: Turn distributed method accessor into async func…
xedin Nov 24, 2021
8980922
[Distributed] IRGen: Mark accessor as `throws` and forward error valu…
xedin Nov 25, 2021
3ec9986
[Distributed] IRGen: Support returning results indirectly from accessor
xedin Nov 27, 2021
7190e9e
[SIL] IR: Make sure that distributed thunk is always emitted
xedin Nov 29, 2021
176b545
[Distributed] IRGen: Switch accessor over to distributed thunk
xedin Nov 29, 2021
56fdf34
[Distributed] NFC: Remove outdated FIXME about async task/executor pa…
xedin Nov 30, 2021
71e7355
[Distributed] IRGen: Don't load arguments they turn into `void` in na…
xedin Dec 1, 2021
2156fb0
[Distributed/Accessor] IRGen: Don't move argument buffer pointer past…
xedin Dec 1, 2021
38a0e66
[Distributed/IRGen] NFC: Add various test-cases for distributed acces…
xedin Dec 2, 2021
8e1aa19
[Mangling] Define mangling for runtime accessible function records
xedin Dec 2, 2021
ef4e94e
[Distributed] IRGen: Define a runtime record for accessible functions
xedin Dec 3, 2021
a831017
[IRGen] Implement accessible function section/record emission
xedin Dec 3, 2021
0060859
[Distributed] IRGen: Don't allocate offset pointer if there is nothin…
xedin Dec 3, 2021
be08a8b
[Distributed] IRGen: Pluralize the name of accessible functions section
xedin Dec 6, 2021
3f4c06e
[Distributed] Runtime: Add skeleton support for accessible function s…
xedin Dec 6, 2021
7eee8c0
[Distributed] Runtime: Cache previously requested accessible functions
xedin Dec 6, 2021
d65906b
[Runtime] Expose accessible function lookup as stdlib SPI
xedin Dec 7, 2021
5af5501
[Distributed] Runtime: Prototype `executeDistributedTarget` function
xedin Dec 7, 2021
7ac42e1
[Distributed] IRGen: Store async function pointer to distributed acce…
xedin Dec 8, 2021
ed97120
[Distributed] Runtime: Implement `_executeDistributedTarget`
xedin Dec 9, 2021
111ceb1
[Distributed] IRGen: Adjust distributed method accessor to store resu…
xedin Dec 10, 2021
dd0d5a8
[Distributed] Remove outdated declaration of `_executeDistributedTarg…
xedin Dec 14, 2021
151bae1
[Distributed] NFC: Update accessor test-cases to use `FakeActorSystem…
xedin Dec 15, 2021
9b21742
[Distributed] Adjust accessor tests to match Windows/Linux section na…
xedin Dec 15, 2021
304f3db
[Distributed] IRGen: Load arguments directly into argument explosion
xedin Dec 17, 2021
2180e4d
[Distributed] IRGen: Make sure that arguments extracted from buffer h…
xedin Dec 17, 2021
bc09fa3
[Distributed] NFC: Remove `align 8` from the accessor thunks test-cases
xedin Dec 17, 2021
8d14443
[Distributed] Runtime: Fix accessor section test-case to support 32/6…
xedin Dec 17, 2021
351300e
[Distributed] Runtime/NFC: Split accessor thunk tests into 32/64 bit …
xedin Dec 17, 2021
d6d9b55
[Distributed] Temporary disable accessor tests on Windows
xedin Dec 17, 2021
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
2 changes: 2 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ Globals
global ::= opaque-type 'Ho' // opaque type descriptor runtime record
#endif
global ::= protocol-conformance 'Hc' // protocol conformance runtime record
global ::= global 'HF' // accessible function runtime record

global ::= nominal-type 'Mo' // class metadata immediate member base offset

Expand Down Expand Up @@ -218,6 +219,7 @@ types where the metadata itself has unknown layout.)
global ::= global 'TD' // dynamic dispatch thunk
global ::= global 'Td' // direct method reference thunk
global ::= global 'TE' // distributed actor thunk
global ::= global 'TF' // distributed method accessor
global ::= global 'TI' // implementation of a dynamic_replaceable function
global ::= global 'Tu' // async function pointer of a function
global ::= global 'TX' // function pointer of a dynamic_replaceable function
Expand Down
24 changes: 24 additions & 0 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -5036,6 +5036,30 @@ class DynamicReplacementScope
uint32_t getFlags() { return flags; }
};

/// An "accessible" function that can be looked up based on a string key,
/// and then called through a fully-abstracted entry point whose arguments
/// can be constructed in code.
template <typename Runtime>
struct TargetAccessibleFunctionRecord final {
ktoso marked this conversation as resolved.
Show resolved Hide resolved
public:
/// The name of the function, which is a unique string assigned to the
/// function so it can be looked up later.
RelativeDirectPointer<const char, /*nullable*/ false> Name;

/// The Swift function type, encoded as a mangled name.
RelativeDirectPointer<const char, /*nullable*/ false> FunctionType;

/// The fully-abstracted function to call.
///
/// Could be a sync or async function pointer depending on flags.
RelativeDirectPointer<void *, /*nullable*/ false> Function;

/// Flags providing more information about the function.
AccessibleFunctionFlags Flags;
};

using AccessibleFunctionRecord = TargetAccessibleFunctionRecord<InProcess>;

} // end namespace swift

#pragma clang diagnostic pop
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 @@ -2312,6 +2312,21 @@ enum class ContinuationStatus : size_t {
Resumed = 2
};

/// Flags that go in a TargetAccessibleFunction structure.
class AccessibleFunctionFlags : public FlagSet<uint32_t> {
public:
enum {
/// Whether this is a "distributed" actor function.
Distributed = 0,
};

explicit AccessibleFunctionFlags(uint32_t bits) : FlagSet(bits) {}
constexpr AccessibleFunctionFlags() {}

/// Whether the this is a "distributed" actor function.
FLAGSET_DEFINE_FLAG_ACCESSORS(Distributed, isDistributed, setDistributed)
};

} // end namespace swift

#endif // SWIFT_ABI_METADATAVALUES_H
2 changes: 2 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class ASTMangler : public Mangler {
SwiftAsObjCThunk,
ObjCAsSwiftThunk,
DistributedThunk,
DistributedMethodAccessor,
AccessibleFunctionRecord
};

ASTMangler(bool DWARFMangling = false)
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ CONTEXT_NODE(Destructor)
CONTEXT_NODE(DidSet)
NODE(Directness)
NODE(DistributedThunk)
NODE(DistributedMethodAccessor)
NODE(DynamicAttribute)
NODE(DirectMethodReferenceAttribute)
NODE(DynamicSelf)
Expand Down Expand Up @@ -325,5 +326,8 @@ NODE(IndexSubset)
NODE(AsyncAwaitResumePartialFunction)
NODE(AsyncSuspendResumePartialFunction)

// Added in Swift 5.6
NODE(AccessibleFunctionRecord)

#undef CONTEXT_NODE
#undef NODE
44 changes: 43 additions & 1 deletion include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,16 @@ class LinkEntity {
/// name is known.
/// The pointer is a const char* of the name.
KnownAsyncFunctionPointer,

/// The pointer is SILFunction*
DistributedMethodAccessor,
/// An async function pointer for a distributed method accessor.
/// The pointer is a SILFunction*.
DistributedMethodAccessorAsyncPointer,

/// Accessible function record, which describes a function that can be
/// looked up by name by the runtime.
AccessibleFunctionRecord,
};
friend struct llvm::DenseMapInfo<LinkEntity>;

Expand Down Expand Up @@ -1236,6 +1246,13 @@ class LinkEntity {
Kind, unsigned(LinkEntity::Kind::PartialApplyForwarderAsyncFunctionPointer));
break;

case LinkEntity::Kind::DistributedMethodAccessor: {
entity.Data = LINKENTITY_SET_FIELD(
Kind,
unsigned(LinkEntity::Kind::DistributedMethodAccessorAsyncPointer));
break;
}

default:
llvm_unreachable("Link entity kind cannot have an async function pointer");
}
Expand Down Expand Up @@ -1263,6 +1280,24 @@ class LinkEntity {
return entity;
}

static LinkEntity forDistributedMethodAccessor(SILFunction *method) {
LinkEntity entity;
entity.Pointer = method;
entity.SecondaryPointer = nullptr;
entity.Data =
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::DistributedMethodAccessor));
return entity;
}

static LinkEntity forAccessibleFunctionRecord(SILFunction *func) {
LinkEntity entity;
entity.Pointer = func;
entity.SecondaryPointer = nullptr;
entity.Data =
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::AccessibleFunctionRecord));
return entity;
}

LinkEntity getUnderlyingEntityForAsyncFunctionPointer() const {
LinkEntity entity;
entity.Pointer = Pointer;
Expand Down Expand Up @@ -1294,6 +1329,11 @@ class LinkEntity {
Kind, unsigned(LinkEntity::Kind::PartialApplyForwarder));
break;

case LinkEntity::Kind::DistributedMethodAccessorAsyncPointer:
entity.Data = LINKENTITY_SET_FIELD(
Kind, unsigned(LinkEntity::Kind::DistributedMethodAccessor));
break;

default:
llvm_unreachable("Link entity is not an async function pointer");
}
Expand Down Expand Up @@ -1341,7 +1381,9 @@ class LinkEntity {
return getKind() == Kind::AsyncFunctionPointer ||
getKind() == Kind::DynamicallyReplaceableFunctionVariable ||
getKind() == Kind::DynamicallyReplaceableFunctionKey ||
getKind() == Kind::SILFunction;
getKind() == Kind::SILFunction ||
getKind() == Kind::DistributedMethodAccessor ||
getKind() == Kind::AccessibleFunctionRecord;
}

SILFunction *getSILFunction() const {
Expand Down
34 changes: 34 additions & 0 deletions include/swift/Runtime/AccessibleFunction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===---- AcceesibleFunction.h - Runtime accessible functions ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 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
//
//===----------------------------------------------------------------------===//
//
// The runtime interface for functions accessible by name.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_RUNTIME_ACCESSIBLE_FUNCTION_H
#define SWIFT_RUNTIME_ACCESSIBLE_FUNCTION_H

#include "swift/ABI/Metadata.h"

#include <cstdint>

namespace swift {
namespace runtime {

SWIFT_RUNTIME_STDLIB_SPI const AccessibleFunctionRecord *
swift_findAccessibleFunction(const char *targetNameStart,
size_t targetNameLength);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok... so this is good since it just says "name" and not exactly what shape of name it is (mangled, or just full name of the base etc). I remain a little worried worried about how we'll know what name to register methods under (today we do mangled names, but what if we want to do the other scheme -- we'd have to annotate methods I guess), but I guess it'll work out since we'd need annotations for the other scheme anyway perhaps 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might use flags to detect new scheme of naming if we switch to something other than mangled names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My worry is about both "sides" having to use the same scheme so they'd have to be compiled using the same flags, but I guess that's just what we'll live with 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's the unfortunate reality of the situation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh yeah... that's what I kept bringing up as "we change it later" being a problem... so we'll be forever stuck emitting the mangled type names as identifiers, and may be able to–in addition to those–add some shorter names... Unless we know "all sides" of the peers and can decide on a scheme to use with a compilation flag... I guess there's ways out of this corner but it'll be annoying :-/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think if we just wanted to drop all of the type information then it would be pretty easy to handle at runtime because we could just read mangled name from the record, remove the type information and match against the name provided by the caller. We'd only have to do that transformation once per method and cache it, but for other schemes it would be tricker.

Copy link
Contributor

@ktoso ktoso Dec 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I wonder if we could get away with recording using the "full name" and then compare the mangled name if we have it to disambiguate any potential stores with the same name... 🤔

Not a blocker for merging this, but just something to continue thinking about :-)


} // end namespace runtime
} // end namespace swift

#endif
22 changes: 20 additions & 2 deletions include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ enum IsExactSelfClass_t {
IsNotExactSelfClass,
IsExactSelfClass,
};
enum IsDistributed_t {
IsNotDistributed,
IsDistributed,
};

enum class PerformanceConstraints : uint8_t {
None = 0,
Expand Down Expand Up @@ -294,6 +298,9 @@ class SILFunction
/// invoked with a `self` argument of the exact base class type.
unsigned ExactSelfClass : 1;

/// Check whether this is a distributed method.
unsigned IsDistributed : 1;

/// True if this function is inlined at least once. This means that the
/// debug info keeps a pointer to this function.
unsigned Inlined : 1;
Expand Down Expand Up @@ -373,14 +380,16 @@ class SILFunction
SubclassScope classSubclassScope, Inline_t inlineStrategy,
EffectsKind E, const SILDebugScope *debugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass);
IsExactSelfClass_t isExactSelfClass,
IsDistributed_t isDistributed);

static SILFunction *
create(SILModule &M, SILLinkage linkage, StringRef name,
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
Optional<SILLocation> loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic,
IsDistributed_t isDistributed,
IsExactSelfClass_t isExactSelfClass,
IsThunk_t isThunk = IsNotThunk,
SubclassScope classSubclassScope = SubclassScope::NotApplicable,
Expand All @@ -399,7 +408,8 @@ class SILFunction
Inline_t inlineStrategy, EffectsKind E,
const SILDebugScope *DebugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass);
IsExactSelfClass_t isExactSelfClass,
IsDistributed_t isDistributed);

/// Set has ownership to the given value. True means that the function has
/// ownership, false means it does not.
Expand Down Expand Up @@ -747,6 +757,14 @@ class SILFunction
ExactSelfClass = t;
}

IsDistributed_t isDistributed() const {
return IsDistributed_t(IsDistributed);
}
void
setIsDistributed(IsDistributed_t value = IsDistributed_t::IsDistributed) {
IsDistributed = value;
}

/// Get the DeclContext of this function.
DeclContext *getDeclContext() const { return DeclCtxt; }

Expand Down
5 changes: 4 additions & 1 deletion include/swift/SIL/SILFunctionBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,16 @@ class SILFunctionBuilder {
IsSerialized_t isSerialized,
ProfileCounter entryCount,
IsThunk_t isThunk,
IsDynamicallyReplaceable_t isDynamic);
IsDynamicallyReplaceable_t isDynamic,
IsDistributed_t isDistributed);

/// Return the declaration of a function, or create it if it doesn't exist.
SILFunction *getOrCreateFunction(
SILLocation loc, StringRef name, SILLinkage linkage,
CanSILFunctionType type, IsBare_t isBareSILFunction,
IsTransparent_t isTransparent, IsSerialized_t isSerialized,
IsDynamicallyReplaceable_t isDynamic,
IsDistributed_t isDistributed,
ProfileCounter entryCount = ProfileCounter(),
IsThunk_t isThunk = IsNotThunk,
SubclassScope subclassScope = SubclassScope::NotApplicable);
Expand Down Expand Up @@ -102,6 +104,7 @@ class SILFunctionBuilder {
Optional<SILLocation> loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
IsDynamicallyReplaceable_t isDynamic,
IsDistributed_t isDistributed,
ProfileCounter entryCount = ProfileCounter(),
IsThunk_t isThunk = IsNotThunk,
SubclassScope subclassScope = SubclassScope::NotApplicable,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/TypeSubstCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
ParentFunction->getLocation(), MangledName, SILLinkage::Shared,
ParentFunction->getLoweredFunctionType(), ParentFunction->isBare(),
ParentFunction->isTransparent(), ParentFunction->isSerialized(),
IsNotDynamic, 0, ParentFunction->isThunk(),
IsNotDynamic, IsNotDistributed, 0, ParentFunction->isThunk(),
ParentFunction->getClassSubclassScope());
// Increment the ref count for the inlined function, so it doesn't
// get deleted before we can emit abstract debug info for it.
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,8 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) {
case SymbolKind::SwiftAsObjCThunk: return appendOperator("To");
case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO");
case SymbolKind::DistributedThunk: return appendOperator("TE");
case SymbolKind::DistributedMethodAccessor: return appendOperator("TF");
case SymbolKind::AccessibleFunctionRecord: return appendOperator("HF");
}
}

Expand Down
7 changes: 6 additions & 1 deletion lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,14 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) {
case Node::Kind::OutlinedBridgedMethod:
case Node::Kind::MergedFunction:
case Node::Kind::DistributedThunk:
case Node::Kind::DistributedMethodAccessor:
case Node::Kind::DynamicallyReplaceableFunctionImpl:
case Node::Kind::DynamicallyReplaceableFunctionKey:
case Node::Kind::DynamicallyReplaceableFunctionVar:
case Node::Kind::AsyncFunctionPointer:
case Node::Kind::AsyncAwaitResumePartialFunction:
case Node::Kind::AsyncSuspendResumePartialFunction:
case Node::Kind::AccessibleFunctionRecord:
return true;
default:
return false;
Expand Down Expand Up @@ -799,7 +801,7 @@ NodePointer Demangler::demangleOperator() {
return createWithChild(
Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol());

// Runtime records (type/protocol/conformance)
// Runtime records (type/protocol/conformance/function)
case 'c':
return createWithChild(Node::Kind::ProtocolConformanceDescriptorRecord,
popProtocolConformance());
Expand All @@ -809,6 +811,8 @@ NodePointer Demangler::demangleOperator() {
return createWithChild(Node::Kind::OpaqueTypeDescriptorRecord, popNode());
case 'r':
return createWithChild(Node::Kind::ProtocolDescriptorRecord, popProtocol());
case 'F':
return createNode(Node::Kind::AccessibleFunctionRecord);

default:
pushBack();
Expand Down Expand Up @@ -2363,6 +2367,7 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
case 'D': return createNode(Node::Kind::DynamicAttribute);
case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute);
case 'E': return createNode(Node::Kind::DistributedThunk);
case 'F': return createNode(Node::Kind::DistributedMethodAccessor);
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
case 'm': return createNode(Node::Kind::MergedFunction);
Expand Down
12 changes: 12 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ class NodePrinter {
case Node::Kind::ProtocolConformanceRefInProtocolModule:
case Node::Kind::ProtocolConformanceRefInOtherModule:
case Node::Kind::DistributedThunk:
case Node::Kind::DistributedMethodAccessor:
case Node::Kind::DynamicallyReplaceableFunctionKey:
case Node::Kind::DynamicallyReplaceableFunctionImpl:
case Node::Kind::DynamicallyReplaceableFunctionVar:
Expand All @@ -585,6 +586,7 @@ class NodePrinter {
case Node::Kind::IndexSubset:
case Node::Kind::AsyncAwaitResumePartialFunction:
case Node::Kind::AsyncSuspendResumePartialFunction:
case Node::Kind::AccessibleFunctionRecord:
return false;
}
printer_unreachable("bad node kind");
Expand Down Expand Up @@ -1997,6 +1999,16 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
Printer << "distributed thunk for ";
}
return nullptr;
case Node::Kind::DistributedMethodAccessor:
if (!Options.ShortenThunk) {
Printer << "distributed method accessor for ";
}
return nullptr;
case Node::Kind::AccessibleFunctionRecord:
if (!Options.ShortenThunk) {
Printer << "accessible function runtime record for ";
}
return nullptr;
case Node::Kind::DynamicallyReplaceableFunctionKey:
if (!Options.ShortenThunk) {
Printer << "dynamically replaceable key for ";
Expand Down
Loading