Files
swift-mirror/stdlib/toolchain/CompatibilityBytecodeLayouts/BytecodeLayouts.h
Dario Rexin 3cf40ea504 [IRGen] Re-introduce TypeLayout strings (#62059)
* Introduce TypeLayout Strings

Layout strings encode the structure of a type into a byte string that can be
interpreted by a runtime function to achieve a destroy or copy. Rather than
generating ir for a destroy/assignWithCopy/etc, we instead generate a layout
string which encodes enough information for a called runtime function to
perform the operation for us. Value witness functions tend to be quite large,
so this allows us to replace them with a single call instead. This gives us the
option of making a codesize/runtime cost trade off.

* Added Attribute @_GenerateLayoutBytecode

This marks a type definition that should use generic bytecode based
value witnesses rather than generating the standard suite of
value witness functions. This should reduce the codesize of the binary
for a runtime interpretation of the bytecode cost.

* Statically link in implementation

Summary:
This creates a library to store the runtime functions in to deploy to
runtimes that do not implement bytecode layouts. Right now, that is
everything. Once these are added to the runtime itself, it can be used
to deploy to old runtimes.

* Implement Destroy at Runtime Using LayoutStrings

If GenerateLayoutBytecode is enabled, Create a layout string and use it
to call swift_generic_destroy

* Add Resilient type and Archetype Support for BytecodeLayouts

Add Resilient type and Archetype Support to Bytecode Layouts

* Implement Bytecode assign/init with copy/take

Implements swift_generic_initialize and swift_generic_assign to allow copying
types using bytecode based witnesses.

* Add EnumTag Support

* Add IRGen Bytecode Layouts Test

Added a test to ensure layouts are correct and getting generated

* Implement BytecodeLayouts ObjC retain/release

* Fix for Non static alignments in aligned groups

* Disable MultiEnums

MultiEnums currently have some correctness issues with non fixed multienum
types. Disabling them for now then going to attempt a correct implementation in
a follow up patch

* Fixes after merge

* More fixes

* Possible fix for native unowned

* Use TypeInfoeBasedTypeLayoutEntry for all scalars when ForceStructTypeLayouts is disabled

* Remove @_GenerateBytecodeLayout attribute

* Fix typelayout_based_value_witness.swift

Co-authored-by: Gwen Mittertreiner <gwenm@fb.com>
Co-authored-by: Gwen Mittertreiner <gwen.mittertreiner@gmail.com>
2022-11-29 21:05:22 -08:00

302 lines
9.6 KiB
C++

//===--- RuntimeValueWitness.h ---===//
// Swift Language Bytecode Layouts Runtime Implementation
//
// 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 runtime determined value witness functions
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BYTECODE_LAYOUTS_H
#define SWIFT_BYTECODE_LAYOUTS_H
#include "swift/Runtime/Metadata.h"
#include <cstdint>
#include <vector>
// Layouts
//
// enum class LayoutType: char {
// // Scalars
// I8 = 'c',
// I16 = 's',
// I32 = 'l',
// I64 = 'L',
// ErrorReference = 'r',
// NativeStrongReference = 'N',
// NativeUnownedReference = 'n',
// NativeWeakReference = 'W',
// UnknownUnownedReference = 'u',
// UnknownWeakReference = 'w',
// BlockReference = 'b',
// BridgeReference = 'B',
// ObjCReference = 'o',
// ExistentialReference = 'x',
//
// // Enums
// SinglePayloadEnum = 'e',
// MultiPayloadEnum = 'E',
// };
//
// VALUE := STRUCT | ENUM | SCALAR
// SCALAR := 'c'|'s'|'l'|'L'|'C'|'r'|'N'|'n'|'W'|'u'|'w'|'b'|'B'|'o'|'f'|'x'
// ALIGNED_GROUP:= 'a' UINT32 (ALIGNMENT,UINT32,VALUE)+
// ALIGNMENT := '0'|'1'|'2'|'3'|'?'
// ENUM := SINGLEENUM | MULTIENUM
//
// SIZE := uint32 (does network order this need to be specified here?)
//
// // e numEmptyPayloads lengthOfPayload payload
// SINGLEENUM := 'e' SIZE SIZE VALUE
//
// // E numEmptyPayloads numPayloads lengthOfEachPayload payloads
// MULTIENUM := 'E' SIZE SIZE SIZE+ VALUE+
//
// OFFSETS := int32+
//
// Examples:
// struct SomeStruct {
// let a : int8
// let b : int16
// let c : int16
// let d : SomeClass
// }
//
// '1c2s2s3N'
// byte aligned int8
// 2 byte aligned int16
// 2 byte aligned int16
// 4 byte aligned Native Pointer
//
// enum SampleEnum {
// case Payload(s: SomeStruct)
// case None
// case ReallyNone
// }
// 'e(0x00000002)(0x00000008)1c2s2s3N'
// An enum with:
// - 2 empty cases
// - a payload stringlength of 8
// - a struct payload as in the previous example
namespace swift {
enum class LayoutType : char {
// Scalars
I8 = 'c',
I16 = 's',
I32 = 'l',
I64 = 'L',
ErrorReference = 'r',
NativeStrongReference = 'N',
NativeUnownedReference = 'n',
NativeWeakReference = 'W',
UnknownUnownedReference = 'u',
UnknownWeakReference = 'w',
BlockReference = 'b',
BridgeReference = 'B',
ObjCReference = 'o',
// Enums
// Single
// e{emptycases}{payload}
//
// Multi
// e{emptycases}{num_cases}{payload1}{payload2}{...}{payloadn}
SinglePayloadEnum = 'e',
MultiPayloadEnum = 'E',
AlignedGroup = 'a',
ArcheType = 'A',
ResilientType = 'R',
};
// The implemenation of this should be provided by the stdlib when we link this
// into an executable/library.
SWIFT_RUNTIME_EXPORT
SWIFT_CC(swift)
const Metadata *swift_getTypeByMangledNameInContext(
const char *typeNameStart, size_t typeNameLength,
const TargetContextDescriptor<InProcess> *context,
const void *const *genericArgs);
SWIFT_RUNTIME_EXPORT
void swift_generic_destroy(void *address, void *metadata,
const uint8_t *typeLayout);
SWIFT_RUNTIME_EXPORT
void swift_generic_assign(void *dest, void *src, void *metadata,
const uint8_t *typeLayout, bool isTake);
SWIFT_RUNTIME_EXPORT
void swift_generic_initialize(void *dest, void *src, void *metadata,
const uint8_t *typeLayout, bool isTake);
} // namespace swift
/// A simple version of swift/Basic/ClusteredBitVector that doesn't use
/// llvm::APInt. Were we to uses ClustedBitVector, we would have to link the
/// implementation into every Swift binary which would be unideal.
struct BitVector {
std::vector<bool> data;
BitVector() = default;
BitVector(std::vector<uint8_t> values);
/// Return a bitvector which the given number of bytes set to all 0s
BitVector(size_t bits);
/// Return the number of set bits in the bit vector
size_t count() const;
/// Append on a byte
void add(uint8_t values);
/// Append on a 32bit value
void add(uint32_t values);
/// Append on a 64bit value
void add(uint64_t values);
/// Append on a vector of bytes
void add(std::vector<uint8_t> values);
/// Append on another bitvector
void add(BitVector v);
/// True if all bits are 0
bool none() const;
/// True if any bit is a 1
bool any() const;
/// Number of bits in the vector
size_t size() const;
/// Zero extend a bit vector to a given number of bits
void zextTo(size_t numBits);
/// Truncate a bitvector to a given number of bits
void truncateTo(size_t numBits);
/// Extend or truncate a bitvector to a given number of bits
void zextOrTruncTo(size_t numBits);
/// Convert to a uint32_t
uint32_t getAsU32() const;
/// Bitwise &= with another vector of the same length
BitVector &operator&=(const BitVector &other);
BitVector operator+(const BitVector &other) const;
/// Return a new bitvector that is the bitwise not of this one
BitVector operator~() const;
/// Number of extra inhabitants that fit into this vector
uint32_t countExtraInhabitants() const;
/// Pack masked bits into the low bits of an integer value.
/// Equivalent to a parallel bit extract instruction (PEXT)
uint32_t gatherBits(BitVector mask);
static BitVector getBitsSetFrom(uint32_t numBits, uint32_t loBits);
};
uint32_t indexFromValue(BitVector mask, BitVector value, BitVector tagBits);
uint32_t extractBits(BitVector mask, BitVector value);
/// Get the sparebits mask and the offset that it's located at
BitVector spareBits(const uint8_t *typeLayout, swift::Metadata *metadata);
size_t computeSize(const uint8_t *typeLayout, swift::Metadata *metadata);
uint32_t getEnumTag(void *addr, const uint8_t *layoutString,
swift::Metadata *metadata);
uint32_t numExtraInhabitants(const uint8_t *layoutString,
swift::Metadata *metadata);
uint32_t getEnumTagMultiPayload(void *addr, const uint8_t *layoutString,
swift::Metadata *metadata);
uint32_t getEnumTagSinglePayload(void *addr, const uint8_t *layoutString,
uint32_t numEmptyPayloads,
swift::Metadata *metadata);
struct AlignedGroup {
struct Field {
Field(uint8_t alignment, uint32_t fieldLength, const uint8_t *fieldPtr)
: alignment(alignment), fieldLength(fieldLength), fieldPtr(fieldPtr) {}
uint8_t alignment;
uint32_t fieldLength;
const uint8_t *fieldPtr;
};
AlignedGroup(std::vector<AlignedGroup::Field> fields,
swift::Metadata *metadata)
: fields(fields), metadata(metadata) {}
std::vector<Field> fields;
swift::Metadata *metadata;
BitVector spareBits() const;
size_t size() const;
};
struct SinglePayloadEnum {
SinglePayloadEnum(uint32_t numEmptyPayloads, uint32_t payloadLayoutLength,
uint32_t payloadSize, uint32_t tagsInExtraInhabitants,
BitVector spareBits, BitVector payloadSpareBits,
const uint8_t *payloadLayoutPtr, uint8_t tagSize,
swift::Metadata *metadata)
: numEmptyPayloads(numEmptyPayloads),
payloadLayoutLength(payloadLayoutLength),
payloadLayoutPtr(payloadLayoutPtr), payloadSize(payloadSize),
tagsInExtraInhabitants(tagsInExtraInhabitants), spareBits(spareBits),
payloadSpareBits(payloadSpareBits), tagSize(tagSize),
size(payloadSize + tagSize), metadata(metadata) {}
uint32_t numEmptyPayloads;
uint32_t payloadLayoutLength;
const uint8_t *payloadLayoutPtr;
uint32_t payloadSize;
uint32_t tagsInExtraInhabitants;
BitVector spareBits;
BitVector payloadSpareBits;
uint8_t tagSize;
uint8_t size;
swift::Metadata *metadata;
};
struct MultiPayloadEnum {
MultiPayloadEnum(uint32_t numEmptyPayloads,
std::vector<uint32_t> payloadLayoutLength,
BitVector extraTagBitsSpareBits,
std::vector<const uint8_t *> payloadLayoutPtr,
swift::Metadata *metadata)
: numEmptyPayloads(numEmptyPayloads),
payloadLayoutLength(payloadLayoutLength),
payloadLayoutPtr(payloadLayoutPtr),
extraTagBitsSpareBits(extraTagBitsSpareBits), metadata(metadata) {}
const uint32_t numEmptyPayloads;
const std::vector<uint32_t> payloadLayoutLength;
const std::vector<const uint8_t *> payloadLayoutPtr;
const BitVector extraTagBitsSpareBits;
swift::Metadata *metadata;
// The spare bits shared by all payloads, if any.
// Invariant: The size of the bit vector is the size of the payload in bits,
// rounded up to a byte boundary.
const BitVector commonSpareBits() const;
uint32_t payloadSize() const;
BitVector spareBits() const;
uint32_t size() const;
uint32_t tagSize() const;
uint32_t tagsInExtraInhabitants() const;
uint32_t gatherSpareBits(const uint8_t *data, unsigned resultBitWidth) const;
};
AlignedGroup readAlignedGroup(const uint8_t *typeLayout,
swift::Metadata *metadata);
MultiPayloadEnum readMultiPayloadEnum(const uint8_t *typeLayout,
swift::Metadata *metadata);
SinglePayloadEnum readSinglePayloadEnum(const uint8_t *typeLayout,
swift::Metadata *metadata);
#endif // SWIFT_BYTECODE_LAYOUTS_H