Files
swift-mirror/stdlib/public/runtime/Array.cpp
Greg Parker e223f1fc9b [IRGen][runtime] Simplify runtime CCs and entry point ABIs (#14175)
* Remove RegisterPreservingCC. It was unused.
* Remove DefaultCC from the runtime. The distinction between C_CC and DefaultCC
  was unused and inconsistently applied. Separate C_CC and DefaultCC are
  still present in the compiler.
* Remove function pointer indirection from runtime functions except those
  that are used by Instruments. The remaining Instruments interface is
  expected to change later due to function pointer liability.
* Remove swift_rt_ wrappers. Function pointers are an ABI liability that we
  don't want, and there are better ways to get nonlazy binding if we need it.
  The fully custom wrappers were only needed for RegisterPreservingCC and
  for optimizing the Instruments function pointers.
2018-01-29 13:22:30 -08:00

211 lines
7.0 KiB
C++

//===------------- Array.cpp - Swift Array Operations Support -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// Implementations of the array runtime functions.
//
// arrayInitWithCopy(T *dest, T *src, size_t count, M* self)
// arrayInitWithTake(NoAlias|FrontToBack|BackToFront)(T *dest, T *src,
// size_t count, M* self)
// arrayAssignWithCopy(NoAlias|FrontToBack|BackToFront)(T *dest, T *src,
// size_t count, M* self)
// arrayAssignWithTake(T *dest, T *src, size_t count, M* self)
// arrayDestroy(T *dst, size_t count, M* self)
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Config.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
using namespace swift;
namespace {
enum class ArrayCopy : unsigned {
NoAlias = 0,
FrontToBack = 1,
BackToFront = 2
};
enum class ArraySource {
Copy,
Take
};
enum class ArrayDest {
Init,
Assign
};
} // end anonymous namespace.
static void array_pod_copy(ArrayCopy copyKind, OpaqueValue *dest,
OpaqueValue *src, size_t stride, size_t count) {
if (copyKind == ArrayCopy::NoAlias) {
memcpy(dest, src, stride * count);
return;
}
assert(copyKind == ArrayCopy::FrontToBack ||
copyKind == ArrayCopy::BackToFront);
memmove(dest, src, stride * count);
}
namespace {
typedef OpaqueValue *(*const WitnessFunction)(OpaqueValue *, OpaqueValue *,
const Metadata *);
}
template <ArrayDest destOp, ArraySource srcOp>
static WitnessFunction get_witness_function(const ValueWitnessTable *wtable) {
if (destOp == ArrayDest::Init) {
if (srcOp == ArraySource::Copy)
return wtable->initializeWithCopy;
else {
assert(srcOp == ArraySource::Take);
return wtable->initializeWithTake;
}
} else {
assert(destOp == ArrayDest::Assign);
if (srcOp == ArraySource::Copy) {
return wtable->assignWithCopy;
} else {
assert(srcOp == ArraySource::Take);
return wtable->assignWithTake;
}
}
}
template <ArrayDest destOp, ArraySource srcOp, ArrayCopy copyKind>
static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
if (count == 0)
return;
auto wtable = self->getValueWitnesses();
auto stride = wtable->getStride();
// If we are doing a copy we need PODness for a memcpy.
if (srcOp == ArraySource::Copy) {
auto isPOD = wtable->isPOD();
if (isPOD) {
array_pod_copy(copyKind, dest, src, stride, count);
return;
}
} else {
// Otherwise, we are doing a take and need bitwise takability for a copy.
assert(srcOp == ArraySource::Take);
auto isBitwiseTakable = wtable->isBitwiseTakable();
if (isBitwiseTakable && (destOp == ArrayDest::Init || wtable->isPOD())) {
array_pod_copy(copyKind, dest, src, stride, count);
return;
}
}
// Call the witness to do the copy.
if (copyKind == ArrayCopy::NoAlias || copyKind == ArrayCopy::FrontToBack) {
auto copy = get_witness_function<destOp, srcOp>(wtable);
for (size_t i = 0; i < count; ++i) {
auto offset = i * stride;
auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset);
auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset);
copy(to, from, self);
}
return;
}
// Back-to-front copy.
assert(copyKind == ArrayCopy::BackToFront);
assert(count != 0);
auto copy = get_witness_function<destOp, srcOp>(wtable);
size_t i = count;
do {
auto offset = --i * stride;
auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset);
auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset);
copy(to, from, self);
} while (i != 0);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayInitWithCopy(OpaqueValue *dest, OpaqueValue *src, size_t count,
const Metadata *self) {
array_copy_operation<ArrayDest::Init, ArraySource::Copy, ArrayCopy::NoAlias>(
dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayInitWithTakeNoAlias(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Init, ArraySource::Take, ArrayCopy::NoAlias>(
dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayInitWithTakeFrontToBack(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Init, ArraySource::Take,
ArrayCopy::FrontToBack>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayInitWithTakeBackToFront(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Init, ArraySource::Take,
ArrayCopy::BackToFront>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayAssignWithCopyNoAlias(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
ArrayCopy::NoAlias>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayAssignWithCopyFrontToBack(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
ArrayCopy::FrontToBack>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayAssignWithCopyBackToFront(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
ArrayCopy::BackToFront>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayAssignWithTake(OpaqueValue *dest, OpaqueValue *src,
size_t count, const Metadata *self) {
array_copy_operation<ArrayDest::Assign, ArraySource::Take,
ArrayCopy::NoAlias>(dest, src, count, self);
}
SWIFT_RUNTIME_EXPORT
void swift_arrayDestroy(OpaqueValue *begin, size_t count, const Metadata *self) {
if (count == 0)
return;
auto wtable = self->getValueWitnesses();
// Nothing to do if the type is POD.
if (wtable->isPOD())
return;
auto stride = wtable->getStride();
for (size_t i = 0; i < count; ++i) {
auto offset = i * stride;
auto *obj = reinterpret_cast<OpaqueValue *>((char *)begin + offset);
wtable->destroy(obj, self);
}
}