diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 7aa2e0fad1b..469d03be712 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -227,13 +227,14 @@ static llvm::Function *createSizeFn(IRGenModule &IGM, } namespace { - /// A CRTP class for laying out class metadata. + enum { NumStandardMetadataFields = 2 }; + + /// A CRTP class for laying out class metadata. Note that this does + /// *not* handle the metadata template stuff. template class MetadataLayout { Impl &asImpl() { return *static_cast(this); } protected: - enum { NumStandardMetadataFields = 2 }; - IRGenModule &IGM; /// The most-derived class. @@ -249,16 +250,17 @@ namespace { asImpl().addSizeFunction(); // Class-specific fields. - addClassFields(TargetClass); + asImpl().addClassFields(TargetClass); } - private: + protected: + /// Add fields associated with the given class and its bases. void addClassFields(ClassDecl *theClass) { // TODO: base class // TODO: virtual methods - if (auto generics = theClass->getGenericParams()) { + if (auto generics = theClass->getGenericParamsOfContext()) { addGenericClassFields(theClass, *generics); } } @@ -281,21 +283,27 @@ namespace { } }; - class MetadataBuilder : public MetadataLayout { - SmallVector Fields; - const HeapLayout &Layout; + template + class MetadataBuilderBase : public MetadataLayout { + typedef MetadataLayout super; + + protected: + SmallVector Fields; + const HeapLayout &Layout; + + MetadataBuilderBase(IRGenModule &IGM, ClassDecl *theClass, + const HeapLayout &layout) + : super(IGM, theClass), Layout(layout) {} + + unsigned getNextIndex() const { return Fields.size(); } public: - MetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, - const HeapLayout &layout) - : MetadataLayout(IGM, theClass), Layout(layout) {} - void addDestructorFunction() { - Fields.push_back(IGM.getAddrOfDestructor(TargetClass)); + Fields.push_back(this->IGM.getAddrOfDestructor(this->TargetClass)); } void addSizeFunction() { - Fields.push_back(createSizeFn(IGM, Layout)); + Fields.push_back(createSizeFn(this->IGM, Layout)); } void beginGenerics(ClassDecl *theClass, const GenericParamList &generics) {} @@ -305,6 +313,22 @@ namespace { Fields.push_back(llvm::Constant::getNullValue(witnessType)); } + llvm::Constant *getInit() { + if (Fields.size() == NumStandardMetadataFields) { + return llvm::ConstantStruct::get(this->IGM.HeapMetadataStructTy, + Fields); + } else { + return llvm::ConstantStruct::getAnon(Fields); + } + } + }; + + class MetadataBuilder : public MetadataBuilderBase { + public: + MetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, + const HeapLayout &layout) + : MetadataBuilderBase(IGM, theClass, layout) {} + llvm::Constant *getInit() { if (Fields.size() == NumStandardMetadataFields) { return llvm::ConstantStruct::get(IGM.HeapMetadataStructTy, Fields); @@ -313,6 +337,127 @@ namespace { } } }; + + /// A builder for metadata templates. + class MetadataTemplateBuilder : + public MetadataBuilderBase { + + typedef MetadataBuilderBase super; + + /// The generics clause for the type we're emitting. + const GenericParamList &ClassGenerics; + + /// The number of generic witnesses in the type we're emitting. + /// This is not really something we need to track. + unsigned NumGenericWitnesses = 0; + + struct FillOp { + unsigned FromIndex; + unsigned ToIndex; + + FillOp() = default; + FillOp(unsigned from, unsigned to) : FromIndex(from), ToIndex(to) {} + }; + + SmallVector FillOps; + + enum { TemplateHeaderFieldCount = 5 }; + + public: + MetadataTemplateBuilder(IRGenModule &IGM, ClassDecl *theClass, + const HeapLayout &layout, + const GenericParamList &classGenerics) + : super(IGM, theClass, layout), ClassGenerics(classGenerics) {} + + void layout() { + // Leave room for the header. + Fields.append(TemplateHeaderFieldCount, nullptr); + + // Lay out the template data. + super::layout(); + + // Fill in the header: + + // uint32_t NumArguments; + + // TODO: ultimately, this should be the number of actual template + // arguments, not the number of value witness tables required. + Fields[0] = llvm::ConstantInt::get(IGM.Int32Ty, NumGenericWitnesses); + + // uint32_t NumFillOps; + Fields[1] = llvm::ConstantInt::get(IGM.Int32Ty, FillOps.size()); + + // size_t MetadataSize; + // We compute this assuming that every entry in the metadata table + // is a pointer. + Size size = getNextIndex() * IGM.getPointerSize(); + Fields[2] = llvm::ConstantInt::get(IGM.SizeTy, size.getValue()); + + // void *PrivateData[8]; + Fields[3] = getPrivateDataInit(); + + // struct SwiftGenericHeapMetadataFillOp FillOps[NumArguments]; + Fields[4] = getFillOpsInit(); + + assert(TemplateHeaderFieldCount == 5); + } + + /// Ignore the preallocated header. + unsigned getNextIndex() const { + return super::getNextIndex() - TemplateHeaderFieldCount; + } + + /// The algorithm we use here is really wrong: we're treating all + /// the witness tables as if they were arguments, then just + /// copying them in-place. + void addGenericWitness(llvm::Type *witnessTy) { + assert(witnessTy->isPointerTy()); + FillOps.push_back(FillOp(NumGenericWitnesses++, getNextIndex())); + super::addGenericWitness(witnessTy); + } + + private: + static llvm::Constant *makeArray(llvm::Type *eltTy, + ArrayRef elts) { + auto arrayTy = llvm::ArrayType::get(eltTy, elts.size()); + return llvm::ConstantArray::get(arrayTy, elts); + } + + /// Produce the initializer for the private-data field of the + /// template header. + llvm::Constant *getPrivateDataInit() { + // Spec'ed to be 8 pointers wide. An arbitrary choice; should + // work out an ideal size with the runtime folks. + auto null = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); + + llvm::Constant *privateData[8] = { + null, null, null, null, null, null, null, null + }; + return makeArray(IGM.Int8PtrTy, privateData); + } + + llvm::Constant *getFillOpsInit() { + // Construct the type of individual operations. + llvm::Type *opMemberTys[] = { IGM.Int32Ty, IGM.Int32Ty }; + auto fillOpTy = + llvm::StructType::get(IGM.getLLVMContext(), opMemberTys, false); + + // Build the array of fill-ops. + SmallVector fillOps(FillOps.size()); + for (size_t i = 0, e = FillOps.size(); i != e; ++i) { + fillOps[i] = getFillOpInit(FillOps[i], fillOpTy); + } + return makeArray(fillOpTy, fillOps); + } + + llvm::Constant *getFillOpInit(const FillOp &op, llvm::StructType *opTy) { + llvm::Constant *members[] = { + llvm::ConstantInt::get(IGM.Int32Ty, op.FromIndex), + llvm::ConstantInt::get(IGM.Int32Ty, op.ToIndex) + }; + return llvm::ConstantStruct::get(opTy, members); + } + }; } /// Emit the heap metadata or metadata template for a class. @@ -321,9 +466,17 @@ void IRGenModule::emitClassMetadata(ClassDecl *classDecl) { auto &classTI = Types.getFragileTypeInfo(classDecl).as(); auto &layout = classTI.getLayout(*this); - MetadataBuilder builder(*this, classDecl, layout); - builder.layout(); - llvm::Constant *init = builder.getInit(); + // TODO: classes nested within generic types + llvm::Constant *init; + if (auto *generics = classDecl->getGenericParamsOfContext()) { + MetadataTemplateBuilder builder(*this, classDecl, layout, *generics); + builder.layout(); + init = builder.getInit(); + } else { + MetadataBuilder builder(*this, classDecl, layout); + builder.layout(); + init = builder.getInit(); + } auto var = cast( getAddrOfClassMetadata(classDecl, init->getType())); @@ -332,9 +485,9 @@ void IRGenModule::emitClassMetadata(ClassDecl *classDecl) { } /// Returns a metadata reference for a constructor. -static llvm::Constant *getClassMetadataForConstructor(IRGenFunction &IGF, - ConstructorDecl *ctor, - ClassDecl *theClass) { +static llvm::Value *getClassMetadataForConstructor(IRGenFunction &IGF, + ConstructorDecl *ctor, + ClassDecl *theClass) { // Grab a reference to the metadata or metadata template. auto metadata = IGF.IGM.getAddrOfClassMetadata(theClass); assert(metadata->getType() == IGF.IGM.HeapMetadataPtrTy); @@ -342,14 +495,65 @@ static llvm::Constant *getClassMetadataForConstructor(IRGenFunction &IGF, // If we don't have generic parameters, that's all we need. // TODO: fragility might force us to indirect this, and startup // performance might force us to do a lazy check. - if (!theClass->getGenericParams()) { + auto classGenerics = theClass->getGenericParamsOfContext(); + if (!classGenerics) { return metadata; } // Okay, we need to call swift_getGenericMetadata. - // Construct our metadata plug-in. - // TODO - return metadata; + + // Grab the substitutions. +#if 0 + CanType thisTy = ctor->getImplicitThisDecl()->getType()->getCanonicalType(); + auto boundGeneric = cast(thisTy); + assert(boundGeneric->getDecl() == theClass); + auto subs = boundGeneric->getSubstitutions(); + // HAHA, there are no substitutions here, you fool. +#else + // Just assume that the archetypes are identical on the + // current context. + auto &ctorGenerics = + cast(ctor->getType())->getGenericParams(); + unsigned numArchetypes = ctorGenerics.getAllArchetypes().size(); + assert(numArchetypes == classGenerics->getAllArchetypes().size()); + SmallVector subs; + for (unsigned i = 0; i != numArchetypes; ++i) { + Substitution sub; + sub.Archetype = classGenerics->getAllArchetypes()[i]; + sub.Replacement = ctorGenerics.getAllArchetypes()[i]; + // conformances not required + subs.push_back(sub); + } +#endif + + // Compile all the generic arguments we need. + Explosion genericArgs(ExplosionKind::Maximal); + emitPolymorphicArguments(IGF, *classGenerics, subs, genericArgs); + + // Slam that information directly into the generic arguments buffer. + // TODO: sort actual arguments to the front. + auto wtableArrayTy = llvm::ArrayType::get(IGF.IGM.WitnessTablePtrTy, + genericArgs.size()); + Address argumentsBuffer = IGF.createAlloca(wtableArrayTy, + IGF.IGM.getPointerAlignment(), + "generic.arguments"); + for (unsigned i = 0, e = genericArgs.size(); i != e; ++i) { + Address elt = IGF.Builder.CreateStructGEP(argumentsBuffer, i, + IGF.IGM.getPointerSize() * i); + IGF.Builder.CreateStore(genericArgs.claimUnmanagedNext(), elt); + } + + // Cast to void*. + llvm::Value *arguments = + IGF.Builder.CreateBitCast(argumentsBuffer.getAddress(), + IGF.IGM.Int8PtrTy); + + // Make the call. + auto result = IGF.Builder.CreateCall2(IGF.IGM.getGetGenericMetadataFn(), + metadata, arguments); + result->setDoesNotThrow(); + + return result; } static void emitClassConstructor(IRGenModule &IGM, ConstructorDecl *CD) { diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 51da3082f05..7776e535f64 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -195,6 +195,19 @@ llvm::Constant *IRGenModule::getDeallocObjectFn() { return DeallocObjectFn; } +llvm::Constant *IRGenModule::getGetGenericMetadataFn() { + if (GetGenericMetadataFn) return GetGenericMetadataFn; + + // heap_metadata_t *swift_getGenericMetadata(heap_metadata_t *pattern, + // const void *arguments); + llvm::Type *argTypes[] = { HeapMetadataPtrTy, Int8PtrTy }; + llvm::FunctionType *fnType = + llvm::FunctionType::get(HeapMetadataPtrTy, argTypes, false); + GetGenericMetadataFn = + createRuntimeFunction(*this, "swift_getGenericMetadata", fnType); + return GetGenericMetadataFn; +} + void IRGenModule::unimplemented(SourceLoc loc, StringRef message) { Context.Diags.diagnose(loc, diag::irgen_unimplemented, message); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index e5e0d24191b..54688254e07 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -166,6 +166,8 @@ public: llvm::Constant *getObjCRetainFn(); llvm::Constant *getObjCReleaseFn(); + llvm::Constant *getGetGenericMetadataFn(); + private: llvm::Function *MemCpyFn; llvm::Constant *AllocObjectFn; @@ -178,6 +180,7 @@ private: llvm::Constant *RawDeallocFn; llvm::Constant *SlowAllocFn; llvm::Constant *SlowRawDeallocFn; + llvm::Constant *GetGenericMetadataFn = nullptr; //--- Generic --------------------------------------------------------------- public: diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 1659b9de606..0c3ba24eacd 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -25,6 +25,7 @@ set(SHARED_LIBRARY ON) add_swift_library(swift_runtime FastEntryPoints.s Alloc.cpp + Metadata.cpp Stubs.cpp ObjCBridge.mm ${CMAKE_BINARY_DIR}/lib/swift.swift) diff --git a/runtime/Makefile b/runtime/Makefile index d7cc723c529..90252ccd53e 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -17,7 +17,7 @@ LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 SWIFT_SOURCES := Bool.swift FixedPoint.swift FloatingPoint.swift String.swift \ Misc.swift Dictionary.swift demangle.swift File.swift Vector.swift Algorithm.swift -SOURCES := FastEntryPoints.s Alloc.cpp Stubs.cpp ObjCBridge.mm swift.swift +SOURCES := FastEntryPoints.s Alloc.cpp Metadata.cpp Stubs.cpp ObjCBridge.mm swift.swift NO_BUILD_ARCHIVE := 1 include $(SWIFT_LEVEL)/../../Makefile.config diff --git a/runtime/Metadata.cpp b/runtime/Metadata.cpp new file mode 100644 index 00000000000..9556f75067e --- /dev/null +++ b/runtime/Metadata.cpp @@ -0,0 +1,122 @@ +//===--- Metadata.cpp - Swift Language ABI Metdata Support ----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Implementations of the metadata ABI functions. +// +//===----------------------------------------------------------------------===// + +#include "Metadata.h" +#include +#include + +namespace { + class MetadataCacheEntry { + const MetadataCacheEntry *Next; + MetadataCacheEntry() = default; + + public: + const MetadataCacheEntry *getNext() const { return Next; } + + void *getArgumentsBuffer() { return this + 1; } + const void *getArgumentsBuffer() const { return this + 1; } + + SwiftHeapMetadata *getMetadataBuffer(SwiftGenericHeapMetadata *pattern) { + return reinterpret_cast( + (reinterpret_cast(getArgumentsBuffer()) + + pattern->NumArguments)); + } + const SwiftHeapMetadata * + getMetadataBuffer(SwiftGenericHeapMetadata *pattern) const { + return const_cast(this)->getMetadataBuffer(pattern); + } + + /// Does this cache entry match the given set of arguments? + bool matches(SwiftGenericHeapMetadata *pattern, + const void *arguments) const { + const void *storedArguments = getArgumentsBuffer(); + + // TODO: exploit alignment and size knowledge. + // NumArguments is always non-zero but will typically be 1. + return memcmp(storedArguments, arguments, + pattern->NumArguments * sizeof(void*)); + } + + /// Allocate and return a new metadata object for the given pattern. + static const SwiftHeapMetadata *create(SwiftGenericHeapMetadata *pattern, + const void *arguments); + }; + + /// The implementation of a metadata cache. Note that all-zero must + /// be a valid state for the cache. + struct MetadataCache { + /// The head of a linked list of metadata cache entries. + const MetadataCacheEntry *Head; + }; + MetadataCache &getCache(SwiftGenericHeapMetadata *metadata) { + return *reinterpret_cast(metadata->PrivateData); + } +} + +// Keep this assert even if you change the representation above. +static_assert(sizeof(MetadataCache) <= + sizeof(SwiftGenericHeapMetadata::PrivateData), + "metadata cache is larger than the allowed space"); + +const SwiftHeapMetadata * +MetadataCacheEntry::create(SwiftGenericHeapMetadata *pattern, + const void *arguments) { + // Allocate the new entry. + void *buffer = operator new(sizeof(MetadataCacheEntry) + + pattern->NumArguments * sizeof(void*) + + pattern->MetadataSize); + MetadataCacheEntry *entry = new (buffer) MetadataCacheEntry(); + + // Copy the arguments into the right place for the key. + memcpy(entry->getArgumentsBuffer(), arguments, + pattern->NumArguments * sizeof(void*)); + + // Initialize the metadata by copying the template. + SwiftHeapMetadata *metadata = entry->getMetadataBuffer(pattern); + memcpy(metadata, pattern->getMetadataTemplate(), pattern->MetadataSize); + + // Fill in the missing spaces from the arguments. + void * const *argumentsAsArray = reinterpret_cast(arguments); + void **metadataAsArray = reinterpret_cast(metadata); + for (auto i = pattern->fill_ops_begin(), + e = pattern->fill_ops_end(); i != e; ++i) { + metadataAsArray[i->ToIndex] = argumentsAsArray[i->FromIndex]; + } + + // The metadata is now valid. + + // Add the cache to the list. This can in theory be made thread-safe, + // but really this should use a non-linear lookup algorithm. + entry->Next = getCache(pattern).Head; + getCache(pattern).Head = entry; + + return metadata; +} + +/// The primary entrypoint. +extern "C" const SwiftHeapMetadata * +swift_getGenericMetadata(SwiftGenericHeapMetadata *pattern, + const void *arguments) { + // Check to see if an entry already exists for these arguments. + for (auto entry = getCache(pattern).Head; + entry != nullptr; entry = entry->getNext()) { + if (entry->matches(pattern, arguments)) + return entry->getMetadataBuffer(pattern); + } + + // Otherwise, create a new one. + return MetadataCacheEntry::create(pattern, arguments); +} diff --git a/runtime/Metadata.h b/runtime/Metadata.h new file mode 100644 index 00000000000..4032aceee69 --- /dev/null +++ b/runtime/Metadata.h @@ -0,0 +1,118 @@ +//===--- Metadata.h - Swift Language ABI Metadata Support -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Swift ABI for generating and uniquing class metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_ABI_METADATA_H +#define SWIFT_ABI_METADATA_H + +#include +#include +#include "FastEntryPoints.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// A heap-metadata fill operation is an instruction to copy a pointer's +/// worth of data from the arguments into a particular position in the +/// allocated metadata. +struct SwiftGenericHeapMetadataFillOp { + uint32_t FromIndex; + uint32_t ToIndex; +}; + +/// \brief The header in front of a generic metadata template. +/// +/// This is optimized so that the code generation pattern +/// requires the minimal number of independent arguments. +/// For example, we want to be able to allocate a generic class +/// Dictionary like so: +/// extern struct SwiftGenericHeapMetadata Dictionary_metadata_header; +/// void *arguments[] = { typeid(T), typeid(U) }; +/// void *metadata = swift_fetchGenericMetadata(&Dictionary_metadata_header, +/// &arguments); +/// void *object = swift_allocObject(metadata); +/// +/// Note that the metadata header is *not* const data; it includes 8 +/// pointers worth of implementation-private data. +/// +/// Both the metadata header and the arguments buffer are guaranteed +/// to be pointer-aligned. +struct SwiftGenericHeapMetadata { + /// The number of generic arguments that we need to unique on, + /// in words. The first 'NumArguments * sizeof(void*)' bytes of + /// the arguments buffer are the key. + uint32_t NumArguments; + + /// The number of fill operations following this header. + /// See the + uint32_t NumFillOps; + + /// The size of the template in bytes. + size_t MetadataSize; + + /// Data that the runtime can use for its own purposes. It is guaranteed + /// to be zero-filled by the compiler. + void *PrivateData[8]; + + // Here there is a variably-sized field: + // struct SwiftGenericHeapMetadataFillOp FillOps[NumArguments]; + + // Here there is a variably-sized field: + // char MetadataTemplate[MetadataSize]; + +#ifdef __cplusplus + typedef SwiftGenericHeapMetadataFillOp FillOp; + typedef const FillOp *fill_ops_const_iterator; + fill_ops_const_iterator fill_ops_begin() const { + return reinterpret_cast(this + 1); + } + fill_ops_const_iterator fill_ops_end() const { + return fill_ops_begin() + NumFillOps; + } + + /// Return the starting address of the metadata template data. + const void *getMetadataTemplate() const { + return fill_ops_end(); + } +#endif +}; + +/// \brief Fetch a uniqued metadata object for a class. +/// +/// The basic algorithm for fetching a metadata object is: +/// func swift_fetchGenericMetadata(header, arguments) { +/// if (metadata = getExistingMetadata(&header.PrivateData, +/// arguments[0..header.NumArguments])) +/// return metadata +/// metadata = malloc(header.MetadataSize) +/// memcpy(metadata, header.MetadataTemplate, header.MetadataSize) +/// for (i in 0..header.NumFillInstructions) +/// metadata[header.FillInstructions[i].ToIndex] +/// = arguments[header.FillInstructions[i].FromIndex] +/// setExistingMetadata(&header.PrivateData, +/// arguments[0..header.NumArguments], +/// metadata) +/// return metadata +/// } +const struct SwiftHeapMetadata * +swift_getGenericMetadata(struct SwiftGenericHeapMetadata *pattern, + const void *arguments); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SWIFT_ABI_METADATA_H */