Upgrade to Pro — share decks privately, control downloads, hide ads and more …

今から使えるSwiftとC++の新しいinterop手法

 今から使えるSwiftとC++の新しいinterop手法

omochimetaru

July 30, 2021
Tweet

More Decks by omochimetaru

Other Decks in Programming

Transcript

  1. ຊ໋ • Interoperability between Swift and C++1 • ଴ͯͳ͍ʂ 1

    https://github.com/apple/swift/blob/main/docs/CppInteroperabilityManifesto.md 4
  2. libswift2 Libswift is the part of the Swift compiler, which

    is implemented in Swift. ... Bridging SIL between C++ and Swift is toll-free, i.e. does not involve any "conversion" between C++ and Swift SIL. 2 https://github.com/apple/swift/tree/main/libswift 5
  3. ValueBase class ValueBase : public SILNode, public SILAllocated<ValueBase> { SILType

    Type; inline use_range getUses() const; } • ϕʔεΫϥε • SILNode: άϥϑػೳ + Swift Interop • SILAllocated: BumpΞϩέʔλ 8
  4. SILType class SILType { using ValueType = llvm::PointerIntPair<TypeBase *, 2,

    unsigned>; ValueType value; } • TypeBase͸ASTεςʔδͷܕ 10
  5. SILInstruction class SILInstruction : public llvm::ilist_node<SILInstruction> { template <typename ContextTy>

    void *operator new(size_t Bytes, const ContextTy &C, size_t Alignment = alignof(ValueBase)) {} SILNode *asSILNode(); } class NonSingleValueInstruction : public SILInstruction, public SILNode {} ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) • ࣮࣭తʹSILNodeΛ਌ʹ࣋ͭɻ 13
  6. SILBasicBlock class SILBasicBlock : public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock>, public SwiftObjectHeader

    { using InstListType = llvm::iplist<SILInstruction>; TinyPtrVector<SILArgument *> ArgumentList; InstListType InstList; } 14
  7. Instruction public class Instruction {} public class SingleValueInstruction : Instruction,

    Value {} public final class MultipleValueInstructionResult : Value {} 19
  8. SwiftObjectHeaderͷ஫ೖ class SILNode: SwiftObjectHeader {} class ValueBase: SILNode {} class

    SILArgument: ValueBase {} class SingleValueInstruction: ValueBase, SILInstruction {} class NonSingleValueInstruction: SILInstruction, SILNode {} class SILBasicBlock: SwiftObjectHeader {} • Կ͔͠ΒSwiftObjectHeaderʹͨͲΓண͘ 23
  9. ࢀরΧ΢ϯλΛ௵͢ ࢀরΧ΢ϯτͷಛఆͷϏοτΛཱ͓ͯͯ͘ͱSwift͸ແࢹ͢Δ3 /* HeapObject { isa InlineRefCounts { atomic<InlineRefCountBits> {

    strong RC + unowned RC + flags OR HeapObjectSideTableEntry* } } } */ struct RefCountBitOffsets<8> { /* ---Immortal case--- All bits set, the object does not deallocate or have a refcount */ } 3 https://github.com/apple/swift/blob/main/stdlib/public/SwiftShims/RefCount.h 24
  10. ϝλΫϥεΛ஫ೖ͢Δ ࣄલʹSwift͔Βऔ͖ͬͯͯC++ʹ౉͢ // Swift @_cdecl("initializeLibSwift") public func initializeLibSwift() { registerSILClasses()

    registerSwiftPasses() } private func register<T: AnyObject>(_ cl: T.Type) { String(describing: cl).withBridgedStringRef { nameStr in let metatype = unsafeBitCast(cl, to: SwiftMetatype.self) registerBridgedClass(nameStr, metatype) } } public func registerSILClasses() { ... register(BasicBlock.self) ... register(StoreInst.self) register(CopyAddrInst.self) register(DeallocStackInst.self) ... } 26
  11. // C++ SwiftMetatype nodeMetatypes[(unsigned)SILNodeKind::Last_SILNode + 1]; void registerBridgedClass(BridgedStringRef className, SwiftMetatype

    metatype) { StringRef clName = getStringRef(className); if (clName == "BasicBlock") return SILBasicBlock::registerBridgedMetatype(metatype); ... nodeMetatypes[(unsigned)kind] = metatype; } ௚઀౉͔͢ςʔϒϧʹ͠·͏ɻ 27
  12. class SILBasicBlock { static SwiftMetatype registeredMetatype; static void registerBridgedMetatype(SwiftMetatype metatype)

    { registeredMetatype = metatype; } } SILBasicBlock::SILBasicBlock() : SwiftObjectHeader(registeredMetatype), Parent(nullptr) {} 28
  13. class SILNode { SILNode(SILNodeKind kind) : SwiftObjectHeader(getSILNodeMetatype(kind)) {} } SwiftMetatype

    SILNode::getSILNodeMetatype(SILNodeKind kind) { SwiftMetatype metatype = nodeMetatypes[(unsigned)kind]; return metatype; } 29
  14. ϒϦοδ༻ͷܕΛఆٛ͢Δ C࣮૷ͳͷͰC++ͱSwift͔Β࢖͑Δ typedef struct { void * _Nullable typePtr; }

    BridgedType; typedef struct { SwiftObject obj; } BridgedValue; typedef struct { SwiftObject obj; } BridgedArgument; typedef struct { SwiftObject obj; } BridgedInstruction; typedef struct { SwiftObject obj; } BridgedBasicBlock; 31
  15. Swift͔ΒC++ͷݺͼग़͠ final public class BasicBlock { public var instructions: List<Instruction>

    { List(startAt: SILBasicBlock_firstInst(bridged).instruction) } var bridged: BridgedBasicBlock { BridgedBasicBlock(obj: SwiftObject(self)) } } 34
  16. SwiftObject SwiftObjectΛSwiftͰ࠶ఆٛɻBridgedSwiftObject͸ڞ༗ɻ AnyObject ͷϙΠϯλΛ௚ม׵ ! public typealias SwiftObject = UnsafeMutablePointer<BridgedSwiftObject>

    extension UnsafeMutablePointer where Pointee == BridgedSwiftObject { init<T: AnyObject>(_ object: T) { let ptr = Unmanaged.passUnretained(object).toOpaque() self = ptr.bindMemory(to: BridgedSwiftObject.self, capacity: 1) } func getAs<T: AnyObject>(_ objectType: T.Type) -> T { return Unmanaged<T>.fromOpaque(self).takeUnretainedValue() } } 35
  17. Optional extension Optional where Wrapped == UnsafeMutablePointer<BridgedSwiftObject> { func getAs<T:

    AnyObject>(_ objectType: T.Type) -> T? { if let pointer = self { return Unmanaged<T>.fromOpaque(pointer).takeUnretainedValue() } return nil } } 36
  18. ࠶ܝ // Swift final public class BasicBlock { var bridged:

    BridgedBasicBlock { BridgedBasicBlock(obj: SwiftObject(self)) } } // C++ struct BridgedSwiftObject { SwiftMetatype metatype; int64_t refCounts; }; typedef struct BridgedSwiftObject * _Nonnull SwiftObject; typedef struct { SwiftObject obj; } BridgedBasicBlock; 37
  19. ॲཧͷϒϦοδ OptionalBridgedInstruction SILBasicBlock_firstInst(BridgedBasicBlock block) { SILBasicBlock *b = castToBasicBlock(block); if

    (b->empty()) return {nullptr}; return {b->front().asSILNode()}; } inline SILBasicBlock *castToBasicBlock(BridgedBasicBlock block) { return static_cast<SILBasicBlock *>(block.obj); } 38
  20. ࠶ܝ class SILNode: SwiftObjectHeader {} struct SwiftObjectHeader : BridgedSwiftObject {}

    typedef struct BridgedSwiftObject * _Nullable OptionalSwiftObject; typedef struct { OptionalSwiftObject obj; } OptionalBridgedInstruction; 39
  21. ࠶ܝ final public class BasicBlock { public var instructions: List<Instruction>

    { List(startAt: SILBasicBlock_firstInst(bridged).instruction) } var bridged: BridgedBasicBlock { BridgedBasicBlock(obj: SwiftObject(self)) } } 40
  22. SwiftଆͰܕ෇͖ͰΞΫηε extension BridgedInstruction { public var instruction: Instruction { obj.getAs(Instruction.self)

    } public func getAs<T: Instruction>(_ instType: T.Type) -> T { obj.getAs(T.self) } } extension OptionalBridgedInstruction { var instruction: Instruction? { obj.getAs(Instruction.self) } } 41
  23. Type // Swift public struct Type { var bridged: BridgedType

    public var isAddress: Bool { SILType_isAddress(bridged) != 0 } public var isObject: Bool { !isAddress } } // C++ typedef struct { void * _Nullable typePtr; } BridgedType; 42
  24. จࣈྻ // C++ typedef struct { const unsigned char *

    _Nullable data; size_t length; } BridgedStringRef; // Swift extension BridgedStringRef { public var string: String { let buffer = UnsafeBufferPointer<UInt8>(start: data, count: Int(length)) return String(decoding: buffer, as: UTF8.self) } func takeString() -> String { let str = string freeBridgedStringRef(self) return str } } 43
  25. callerʹղ์੹೚͕౉Δ৔߹͕͋Δ inline BridgedStringRef getBridgedStringRef(llvm::StringRef str) { return { (const unsigned

    char *)str.data(), str.size() }; } /// Copies the string in an malloc'ed memory and the caller is responsible for /// freeing it. inline BridgedStringRef getCopiedBridgedStringRef(std::string str, bool removeTrailingNewline = false) { // A couple of mallocs are needed for passing a std::string to libswift. But // it's currently only used or debug descriptions. So, its' maybe not so bad - // for now. // TODO: find a better way to pass std::strings to libswift. StringRef strRef(str); if (removeTrailingNewline) strRef.consume_back("\n"); llvm::MallocAllocator allocator; StringRef copy = strRef.copy(allocator); return getBridgedStringRef(copy); } 44
  26. public protocol Value {} extension Value { public var description:

    String { SILNode_debugDescription(bridgedNode).takeString() } var bridgedNode: BridgedNode { BridgedNode(obj: SwiftObject(self as AnyObject)) } } 45
  27. Πϯελϯεੜ੒ ઐ༻ͷBuilderΛ௨ͯ͠C++ଆͰੜ੒͢Δ final public class BuiltinInst : SingleValueInstruction {} public

    class SingleValueInstruction : Instruction, Value {} public class Instruction {} public struct Builder { public func createBuiltinBinaryFunction(name: String, operandType: Type, resultType: Type, arguments: [Value]) -> BuiltinInst { notifyInstructionsChanged() return arguments.withBridgedValues { valuesRef in return name.withBridgedStringRef { nameStr in let bi = SILBuilder_createBuiltinBinaryFunction( bridgedInsPoint, location.bridgedLocation, nameStr, operandType.bridged, resultType.bridged, valuesRef) return bi.getAs(BuiltinInst.self) } } } } 46