Skip to content

[Concurrency] Add compatibility overrides to Concurrency library. #36390

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
merged 1 commit into from
Mar 24, 2021
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
23 changes: 17 additions & 6 deletions include/swift/Runtime/Concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,14 +479,25 @@ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_MainActor_register(HeapObject *actor);

/// A hook to take over global enqueuing.
/// TODO: figure out a better abstraction plan than this.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void (*swift_task_enqueueGlobal_hook)(Job *job);
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobal_original)(Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift) void (*swift_task_enqueueGlobal_hook)(
Job *job, swift_task_enqueueGlobal_original original);

/// A hook to take over global enqueuing with delay.
/// TODO: figure out a better abstraction plan than this.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void (*swift_task_enqueueGlobalWithDelay_hook)(unsigned long long delay, Job *job);
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_original)(
unsigned long long delay, Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_hook)(
unsigned long long delay, Job *job,
swift_task_enqueueGlobalWithDelay_original original);

/// A hook to take over main executor enqueueing.
typedef SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_original)(
Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_hook)(
Job *job, swift_task_enqueueMainExecutor_original original);

/// Initialize the runtime storage for a default actor.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES

#include "CompatibilityOverride.h"

#include "ImageInspection.h"
#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES

#include "../runtime/ImageInspection.h"
#include "swift/Runtime/Once.h"
#include <assert.h>
#include <atomic>
#include <mach-o/getsect.h>
#include <type_traits>

using namespace swift;
Expand All @@ -42,19 +43,38 @@ struct OverrideSection {

#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \
Override_ ## name name;
#include "CompatibilityOverride.def"
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH
};

static_assert(std::is_pod<OverrideSection>::value,
"OverrideSection has a set layout and must be POD.");

// We only support mach-o for overrides, so the implementation of lookupSection
// can be mach-o specific.
#if __POINTER_WIDTH__ == 64
using mach_header_platform = mach_header_64;
#else
using mach_header_platform = mach_header;
#endif

extern "C" mach_header_platform *_NSGetMachExecuteHeader();
static void *lookupSection(const char *segment, const char *section,
size_t *outSize) {
unsigned long size;
auto *executableHeader = _NSGetMachExecuteHeader();
uint8_t *data = getsectiondata(executableHeader, segment, section, &size);
if (outSize != nullptr && data != nullptr)
*outSize = size;
return static_cast<void *>(data);
}

static OverrideSection *getOverrideSectionPtr() {
static OverrideSection *OverrideSectionPtr;
static swift_once_t Predicate;
swift_once(&Predicate, [](void *) {
size_t Size;
OverrideSectionPtr = static_cast<OverrideSection *>(
lookupSection("__DATA", "__swift54_hooks", &Size));
lookupSection("__DATA", COMPATIBILITY_OVERRIDE_SECTION_NAME, &Size));
if (Size < sizeof(OverrideSection))
OverrideSectionPtr = nullptr;
}, nullptr);
Expand All @@ -69,6 +89,6 @@ static OverrideSection *getOverrideSectionPtr() {
return nullptr; \
return Section->name; \
}
#include "CompatibilityOverride.def"
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH

#endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES
136 changes: 136 additions & 0 deletions stdlib/public/CompatibilityOverride/CompatibilityOverride.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// Support back-deploying compatibility fixes for newer apps running on older runtimes.
//
//===----------------------------------------------------------------------===//

#ifndef COMPATIBILITY_OVERRIDE_H
#define COMPATIBILITY_OVERRIDE_H

#include "../runtime/Private.h"
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Runtime/Once.h"
#include <type_traits>

namespace swift {

// Macro utilities.
#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__
#define COMPATIBILITY_CONCAT2(x, y) x##y
#define COMPATIBILITY_CONCAT(x, y) COMPATIBILITY_CONCAT2(x, y)

// This ridiculous construct will remove the parentheses from the argument and
// add a trailing comma, or will produce nothing when passed no argument. For
// example:
// COMPATIBILITY_UNPAREN_WITH_COMMA((1, 2, 3)) -> 1, 2, 3,
// COMPATIBILITY_UNPAREN_WITH_COMMA((4)) -> 4,
// COMPATIBILITY_UNPAREN_WITH_COMMA() ->
#define COMPATIBILITY_UNPAREN_WITH_COMMA(x) \
COMPATIBILITY_CONCAT(COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_, \
COMPATIBILITY_UNPAREN_WITH_COMMA2 x)
#define COMPATIBILITY_UNPAREN_WITH_COMMA2(...) PARAMS(__VA_ARGS__)
#define COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_PARAMS(...) __VA_ARGS__,
#define COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_COMPATIBILITY_UNPAREN_WITH_COMMA2

// This ridiculous construct will preserve the parentheses around the argument,
// or will produce an empty pair of parentheses when passed no argument. For
// example:
// COMPATIBILITY_PAREN((1, 2, 3)) -> (1, 2, 3)
// COMPATIBILITY_PAREN((4)) -> (4)
// COMPATIBILITY_PAREN() -> ()
#define COMPATIBILITY_PAREN(x) \
COMPATIBILITY_CONCAT(COMPATIBILITY_PAREN_, COMPATIBILITY_PAREN2 x)
#define COMPATIBILITY_PAREN2(...) PARAMS(__VA_ARGS__)
#define COMPATIBILITY_PAREN_PARAMS(...) (__VA_ARGS__)
#define COMPATIBILITY_PAREN_COMPATIBILITY_PAREN2 ()

// Include path computation. Code that includes this file can write
// `#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH` to include the appropriate
// .def file for the current library.
#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swiftRuntime \
"../CompatibilityOverride/CompatibilityOverrideRuntime.def"
#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swift_Concurrency \
"../CompatibilityOverride/CompatibilityOverrideConcurrency.def"

#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH \
COMPATIBILITY_CONCAT(COMPATIBILITY_OVERRIDE_INCLUDE_PATH_, \
SWIFT_TARGET_LIBRARY_NAME)

// Compatibility overrides are only supported on Darwin.
#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES
#if !(defined(__APPLE__) && defined(__MACH__))
#define SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES
#endif
#endif

#ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES

// Call directly through to the original implementation when we don't support
// overrides.
#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, \
typedArgs, namedArgs) \
attrs ccAttrs ret namespace swift_##name COMPATIBILITY_PAREN(typedArgs) { \
return swift_##name##Impl COMPATIBILITY_PAREN(namedArgs); \
}

#else // #ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES

// Override section name computation. `COMPATIBILITY_OVERRIDE_SECTION_NAME` will
// resolve to string literal containing the appropriate section name for the
// current library.
#define COMPATIBILITY_OVERRIDE_SECTION_NAME_swiftRuntime "__swift54_hooks"
#define COMPATIBILITY_OVERRIDE_SECTION_NAME_swift_Concurrency "__s_async_hook"

#define COMPATIBILITY_OVERRIDE_SECTION_NAME \
COMPATIBILITY_CONCAT(COMPATIBILITY_OVERRIDE_SECTION_NAME_, \
SWIFT_TARGET_LIBRARY_NAME)

// Create typedefs for function pointers to call the original implementation.
#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \
ccAttrs typedef ret(*Original_##name) COMPATIBILITY_PAREN(typedArgs);
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH

// Create typedefs for override function pointers.
#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \
ccAttrs typedef ret (*Override_##name)(COMPATIBILITY_UNPAREN_WITH_COMMA( \
typedArgs) Original_##name originalImpl);
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH

// Create declarations for getOverride functions.
#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \
Override_ ## name getOverride_ ## name();
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH

/// Used to define an override point. The override point #defines the appropriate
/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes
/// the file to generate the override points. The original implementation of the
/// functionality must be available as swift_funcNameHereImpl.
#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, \
typedArgs, namedArgs) \
attrs ccAttrs ret namespace swift_##name COMPATIBILITY_PAREN(typedArgs) { \
static Override_##name Override; \
static swift_once_t Predicate; \
swift_once( \
&Predicate, [](void *) { Override = getOverride_##name(); }, nullptr); \
if (Override != nullptr) \
return Override(COMPATIBILITY_UNPAREN_WITH_COMMA(namedArgs) \
swift_##name##Impl); \
return swift_##name##Impl COMPATIBILITY_PAREN(namedArgs); \
}

#endif // #else SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES

} /* end namespace swift */

#endif /* COMPATIBILITY_OVERRIDE_H */
Loading