mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
321 lines
14 KiB
C++
321 lines
14 KiB
C++
//===------ Array.cpp - Array runtime function tests ----------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Runtime/Metadata.h"
|
|
#include "swift/Runtime/HeapObject.h"
|
|
#include "swift/Runtime/Concurrent.h"
|
|
#include "swift/Runtime/HeapObject.h"
|
|
#include "swift/Runtime/Metadata.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace swift;
|
|
|
|
namespace swift {
|
|
void installCommonValueWitnesses(const TypeLayout &layout,
|
|
ValueWitnessTable *vwtable);
|
|
} // namespace swift
|
|
|
|
|
|
static void initialize_pod_witness_table_size_uint32_t_stride_uint64_t(
|
|
ValueWitnessTable &testTable) {
|
|
testTable.size = sizeof(uint32_t);
|
|
testTable.flags = ValueWitnessFlags()
|
|
.withAlignment(alignof(ValueBuffer))
|
|
.withPOD(true)
|
|
.withBitwiseTakable(true)
|
|
.withInlineStorage(true);
|
|
testTable.stride = sizeof(uint64_t);
|
|
installCommonValueWitnesses(*testTable.getTypeLayout(), &testTable);
|
|
}
|
|
|
|
extern "C" void swift_arrayInitWithCopy(OpaqueValue *dest,
|
|
OpaqueValue *src, size_t count,
|
|
const Metadata *self);
|
|
|
|
#define COPY_POD_TEST(kind) \
|
|
ValueWitnessTable pod_witnesses; \
|
|
memset(&pod_witnesses, 0, sizeof(pod_witnesses)); \
|
|
initialize_pod_witness_table_size_uint32_t_stride_uint64_t(pod_witnesses); \
|
|
uint64_t srcArray[3] = {0, 1, 2}; \
|
|
uint64_t destArray[3] = {0x5A5A5A5AU, 0x5A5A5A5AU, 0x5A5A5A5AU}; \
|
|
FullOpaqueMetadata testMetadata = {{&pod_witnesses}, \
|
|
{{MetadataKind::Opaque}}}; \
|
|
Metadata *metadata = &testMetadata.base; \
|
|
swift_array##kind((OpaqueValue *)destArray, (OpaqueValue *)srcArray, 3, \
|
|
metadata); \
|
|
EXPECT_EQ(destArray[0], 0u); \
|
|
EXPECT_EQ(destArray[1], 1u); \
|
|
EXPECT_EQ(destArray[2], 2u); \
|
|
\
|
|
EXPECT_EQ(srcArray[0], 0u); \
|
|
EXPECT_EQ(srcArray[1], 1u); \
|
|
EXPECT_EQ(srcArray[2], 2u);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithCopy) {
|
|
COPY_POD_TEST(InitWithCopy);
|
|
}
|
|
|
|
|
|
namespace {
|
|
struct TestObject : HeapObject {
|
|
size_t *Addr;
|
|
size_t Value;
|
|
};
|
|
}
|
|
|
|
static SWIFT_CC(swift) void destroyTestObject(SWIFT_CONTEXT HeapObject *_object) {
|
|
auto object = static_cast<TestObject*>(_object);
|
|
assert(object->Addr && "object already deallocated");
|
|
*object->Addr = object->Value;
|
|
object->Addr = nullptr;
|
|
swift_deallocObject(object, sizeof(TestObject), alignof(TestObject) - 1);
|
|
}
|
|
|
|
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
|
|
{ { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
|
|
{ { nullptr }, ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
/// Create an object that, when deallocated, stores the given value to
|
|
/// the given pointer.
|
|
static TestObject *allocTestObject(size_t *addr, size_t value) {
|
|
auto result =
|
|
static_cast<TestObject *>(swift_allocObject(&TestClassObjectMetadata,
|
|
sizeof(TestObject),
|
|
alignof(TestObject) - 1));
|
|
result->Addr = addr;
|
|
result->Value = value;
|
|
return result;
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithCopyNoAliasNonPOD) {
|
|
size_t object0Val = 0;
|
|
size_t object1Val = 1;
|
|
HeapObject *object0 = allocTestObject(&object0Val, 2);
|
|
HeapObject *object1 = allocTestObject(&object1Val, 3);
|
|
|
|
HeapObject *srcArray[2] = {object0, object1};
|
|
HeapObject *destArray[2] = {(HeapObject *)0x5A5A5A5AU,
|
|
(HeapObject *)0x5A5A5A5AU};
|
|
const Metadata *metadata = &TestClassObjectMetadata;
|
|
swift_arrayInitWithCopy((OpaqueValue *)destArray, (OpaqueValue *)srcArray, 2,
|
|
metadata);
|
|
EXPECT_EQ(destArray[0], object0);
|
|
EXPECT_EQ(destArray[1], object1);
|
|
|
|
EXPECT_EQ(srcArray[0], object0);
|
|
EXPECT_EQ(srcArray[1], object1);
|
|
|
|
EXPECT_EQ(swift_retainCount(object0), 2u);
|
|
EXPECT_EQ(swift_retainCount(object1), 2u);
|
|
|
|
swift_release(object0);
|
|
swift_release(object0);
|
|
swift_release(object1);
|
|
swift_release(object1);
|
|
EXPECT_EQ(object0Val, 2u);
|
|
EXPECT_EQ(object1Val, 3u);
|
|
}
|
|
|
|
extern "C" void swift_arrayInitWithTakeNoAlias(OpaqueValue *dest,
|
|
OpaqueValue *src, size_t count,
|
|
const Metadata *self);
|
|
extern "C" void swift_arrayInitWithTakeFrontToBack(OpaqueValue *dest,
|
|
OpaqueValue *src,
|
|
size_t count,
|
|
const Metadata *self);
|
|
extern "C" void swift_arrayInitWithTakeBackToFront(OpaqueValue *dest,
|
|
OpaqueValue *src,
|
|
size_t count,
|
|
const Metadata *self);
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeNoAliasPOD) {
|
|
COPY_POD_TEST(InitWithTakeNoAlias);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeFrontToBackPOD) {
|
|
COPY_POD_TEST(InitWithTakeFrontToBack);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeBackToFrontPOD) {
|
|
COPY_POD_TEST(InitWithTakeBackToFront);
|
|
}
|
|
|
|
#define INITWITHTAKE_NONPOD_TEST(copy) \
|
|
size_t object0Val = 0; \
|
|
size_t object1Val = 1; \
|
|
HeapObject *object0 = allocTestObject(&object0Val, 2); \
|
|
HeapObject *object1 = allocTestObject(&object1Val, 3); \
|
|
\
|
|
HeapObject *srcArray[2] = {object0, object1}; \
|
|
HeapObject *destArray[2] = {(HeapObject *)0x5A5A5A5AU, \
|
|
(HeapObject *)0x5A5A5A5AU}; \
|
|
const Metadata *metadata = &TestClassObjectMetadata; \
|
|
swift_arrayInitWithTake##copy((OpaqueValue *)destArray, \
|
|
(OpaqueValue *)srcArray, 2, metadata); \
|
|
EXPECT_EQ(destArray[0], object0); \
|
|
EXPECT_EQ(destArray[1], object1); \
|
|
\
|
|
EXPECT_EQ(srcArray[0], object0); \
|
|
EXPECT_EQ(srcArray[1], object1); \
|
|
\
|
|
EXPECT_EQ(swift_retainCount(object0), 1u); \
|
|
EXPECT_EQ(swift_retainCount(object1), 1u); \
|
|
\
|
|
swift_release(object0); \
|
|
swift_release(object1); \
|
|
EXPECT_EQ(object0Val, 2u); \
|
|
EXPECT_EQ(object1Val, 3u);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeNoAliasNonPOD) {
|
|
INITWITHTAKE_NONPOD_TEST(NoAlias);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeFrontToBackNonPOD) {
|
|
INITWITHTAKE_NONPOD_TEST(FrontToBack);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayInitWithTakeBackToFrontNonPOD) {
|
|
INITWITHTAKE_NONPOD_TEST(BackToFront);
|
|
}
|
|
|
|
extern "C" void swift_arrayAssignWithCopyNoAlias(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self);
|
|
extern "C" void swift_arrayAssignWithCopyFrontToBack(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self);
|
|
extern "C" void swift_arrayAssignWithCopyBackToFront(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyNoAliasPOD) {
|
|
COPY_POD_TEST(AssignWithCopyNoAlias);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyFrontToBackPOD) {
|
|
COPY_POD_TEST(AssignWithCopyFrontToBack);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyBackToFrontPOD) {
|
|
COPY_POD_TEST(AssignWithCopyBackToFront);
|
|
}
|
|
|
|
#define ASSIGNWITHCOPY_NONPOD_TEST(copy) \
|
|
size_t object0Val = 0; \
|
|
size_t object1Val = 1; \
|
|
HeapObject *object0 = allocTestObject(&object0Val, 2); \
|
|
HeapObject *object1 = allocTestObject(&object1Val, 3); \
|
|
size_t object2Val = 4; \
|
|
size_t object3Val = 5; \
|
|
HeapObject *object2 = allocTestObject(&object2Val, 6); \
|
|
HeapObject *object3 = allocTestObject(&object3Val, 7); \
|
|
\
|
|
HeapObject *srcArray[2] = {object0, object1}; \
|
|
HeapObject *destArray[2] = {object2, object3}; \
|
|
const Metadata *metadata = &TestClassObjectMetadata; \
|
|
swift_arrayAssignWithCopy##copy((OpaqueValue *)destArray, \
|
|
(OpaqueValue *)srcArray, 2, metadata); \
|
|
EXPECT_EQ(destArray[0], object0); \
|
|
EXPECT_EQ(destArray[1], object1); \
|
|
\
|
|
EXPECT_EQ(srcArray[0], object0); \
|
|
EXPECT_EQ(srcArray[1], object1); \
|
|
\
|
|
EXPECT_EQ(swift_retainCount(object0), 2u); \
|
|
EXPECT_EQ(swift_retainCount(object1), 2u); \
|
|
\
|
|
EXPECT_EQ(object2Val, 6u); \
|
|
EXPECT_EQ(object3Val, 7u); \
|
|
\
|
|
swift_release(object0); \
|
|
swift_release(object0); \
|
|
swift_release(object1); \
|
|
swift_release(object1); \
|
|
EXPECT_EQ(object0Val, 2u); \
|
|
EXPECT_EQ(object1Val, 3u);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyNoAliasNonPOD) {
|
|
ASSIGNWITHCOPY_NONPOD_TEST(NoAlias);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyFrontToBackNonPOD) {
|
|
ASSIGNWITHCOPY_NONPOD_TEST(FrontToBack);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithCopyBackToFrontNonPOD) {
|
|
ASSIGNWITHCOPY_NONPOD_TEST(BackToFront);
|
|
}
|
|
|
|
extern "C" void swift_arrayAssignWithTake(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithTakePOD) {
|
|
COPY_POD_TEST(AssignWithTake);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayAssignWithTakeNonPOD) {
|
|
size_t object0Val = 0;
|
|
size_t object1Val = 1;
|
|
HeapObject *object0 = allocTestObject(&object0Val, 2);
|
|
HeapObject *object1 = allocTestObject(&object1Val, 3);
|
|
size_t object2Val = 4;
|
|
size_t object3Val = 5;
|
|
HeapObject *object2 = allocTestObject(&object2Val, 6);
|
|
HeapObject *object3 = allocTestObject(&object3Val, 7);
|
|
|
|
HeapObject *srcArray[2] = {object0, object1};
|
|
HeapObject *destArray[2] = {object2, object3};
|
|
const Metadata *metadata = &TestClassObjectMetadata;
|
|
swift_arrayAssignWithTake((OpaqueValue *)destArray, (OpaqueValue *)srcArray,
|
|
2, metadata);
|
|
EXPECT_EQ(destArray[0], object0);
|
|
EXPECT_EQ(destArray[1], object1);
|
|
|
|
EXPECT_EQ(srcArray[0], object0);
|
|
EXPECT_EQ(srcArray[1], object1);
|
|
|
|
EXPECT_EQ(swift_retainCount(object0), 1u);
|
|
EXPECT_EQ(swift_retainCount(object1), 1u);
|
|
|
|
EXPECT_EQ(object2Val, 6u);
|
|
EXPECT_EQ(object3Val, 7u);
|
|
|
|
swift_release(object0);
|
|
swift_release(object1);
|
|
EXPECT_EQ(object0Val, 2u);
|
|
EXPECT_EQ(object1Val, 3u);
|
|
}
|
|
|
|
extern "C" void swift_arrayDestroy(OpaqueValue *begin, size_t count,
|
|
const Metadata *self);
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayDestroyPOD) {
|
|
ValueWitnessTable pod_witnesses;
|
|
memset(&pod_witnesses, 0, sizeof(pod_witnesses));
|
|
initialize_pod_witness_table_size_uint32_t_stride_uint64_t(pod_witnesses);
|
|
uint64_t array[3] = {0, 1, 2};
|
|
FullOpaqueMetadata testMetadata = {{&pod_witnesses},
|
|
{{MetadataKind::Opaque}}};
|
|
Metadata *metadata = &testMetadata.base;
|
|
// Let's make sure this does not crash.
|
|
swift_arrayDestroy((OpaqueValue *)array, 3, metadata);
|
|
}
|
|
|
|
TEST(TestArrayCopy, test_swift_arrayDestroyNonPOD) {
|
|
size_t object0Val = 0;
|
|
size_t object1Val = 1;
|
|
HeapObject *object0 = allocTestObject(&object0Val, 2);
|
|
HeapObject *object1 = allocTestObject(&object1Val, 3);
|
|
HeapObject *array[2] = {object0, object1};
|
|
const Metadata *metadata = &TestClassObjectMetadata;
|
|
swift_arrayDestroy((OpaqueValue *)array, 2, metadata);
|
|
EXPECT_EQ(object0Val, 2u);
|
|
EXPECT_EQ(object1Val, 3u);
|
|
}
|