//===--- GenKeyPath.cpp - IRGen support for key path objects --------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file contains code for emitting key path patterns, which can be used // by the standard library to instantiate key path objects. // //===----------------------------------------------------------------------===// #include "GenKeyPath.h" #include "Callee.h" #include "ClassLayout.h" #include "ConstantBuilder.h" #include "Explosion.h" #include "GenClass.h" #include "GenDecl.h" #include "GenMeta.h" #include "GenPointerAuth.h" #include "GenProto.h" #include "GenStruct.h" #include "GenTuple.h" #include "GenType.h" #include "GenericRequirement.h" #include "IRGenDebugInfo.h" #include "IRGenFunction.h" #include "IRGenMangler.h" #include "IRGenModule.h" #include "LoadableTypeInfo.h" #include "MetadataLayout.h" #include "ProtocolInfo.h" #include "StructLayout.h" #include "TypeInfo.h" #include "llvm/ADT/SetVector.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/TypeLowering.h" #include "swift/ABI/KeyPath.h" #include "swift/ABI/HeapObject.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsIRGen.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Statistic.h" #include "swift/IRGen/Linking.h" using namespace swift; using namespace irgen; #define DEBUG_TYPE "IRGen key paths" STATISTIC(NumTrivialPropertyDescriptors, "# of trivial property descriptors"); STATISTIC(NumNonTrivialPropertyDescriptors, "# of nontrivial property descriptors"); enum KeyPathAccessor { Getter, Setter, Equals, Hash, }; void irgen::bindPolymorphicArgumentsFromComponentIndices(IRGenFunction &IGF, GenericEnvironment *genericEnv, ArrayRef requirements, llvm::Value *args, llvm::Value *size, bool hasSubscriptIndices) { if (!genericEnv) return; // The generic environment is marshaled into the end of the component // argument area inside the instance. Bind the generic information out of // the buffer. auto genericArgsSize = llvm::ConstantInt::get(IGF.IGM.SizeTy, requirements.size() * IGF.IGM.getPointerSize().getValue()); auto genericArgsOffset = IGF.Builder.CreateSub(size, genericArgsSize); args = IGF.Builder.CreateInBoundsGEP(IGF.IGM.Int8Ty, args, genericArgsOffset); bindFromGenericRequirementsBuffer( IGF, requirements, Address(args, IGF.IGM.Int8Ty, IGF.IGM.getPointerAlignment()), MetadataState::Complete, genericEnv->getForwardingSubstitutionMap()); } static llvm::Function * getAccessorForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, KeyPathAccessor whichAccessor) { SILFunction *accessor; switch (whichAccessor) { case Getter: accessor = component.getComputedPropertyForGettable(); break; case Setter: accessor = component.getComputedPropertyForSettable(); break; case Equals: accessor = component.getIndexEquals(); break; case Hash: accessor = component.getIndexHash(); break; } // If the accessor is locally available, we can use it as is. // If it's only externally available, we need a local thunk to relative- // reference. if (!isAvailableExternally(accessor->getLinkage()) && &IGM == IGM.IRGen.getGenModule(accessor)) { return IGM.getAddrOfSILFunction(accessor, NotForDefinition); } const char *thunkName; switch (whichAccessor) { case Getter: thunkName = "keypath_get"; break; case Setter: thunkName = "keypath_set"; break; case Equals: thunkName = "keypath_equals"; break; case Hash: thunkName = "keypath_hash"; break; } auto accessorFn = IGM.getAddrOfSILFunction(accessor, NotForDefinition); auto accessorThunk = llvm::Function::Create(accessorFn->getFunctionType(), llvm::GlobalValue::PrivateLinkage, thunkName, IGM.getModule()); accessorThunk->setAttributes(IGM.constructInitialAttributes()); accessorThunk->setCallingConv(IGM.SwiftCC); accessorThunk->setAttributes(accessorFn->getAttributes()); { IRGenFunction IGF(IGM, accessorThunk); if (IGM.DebugInfo) IGM.DebugInfo->emitArtificialFunction(IGF, accessorThunk); Explosion forwardedArgs = IGF.collectParameters(); auto fnPtr = FunctionPointer::forDirect(IGM, accessorFn, /*secondaryValue*/ nullptr, accessor->getLoweredFunctionType()); auto call = IGF.Builder.CreateCall(fnPtr, forwardedArgs.claimAll()); if (call->getType()->isVoidTy()) IGF.Builder.CreateRetVoid(); else IGF.Builder.CreateRet(call); } return accessorThunk; } static llvm::Function * getLayoutFunctionForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, GenericEnvironment *genericEnv, ArrayRef requirements) { // Generate a function that returns the expected size and alignment necessary // to store captured generic context and subscript index arguments. auto retTy = llvm::StructType::get(IGM.getLLVMContext(), {IGM.SizeTy, IGM.SizeTy}); auto fnTy = llvm::FunctionType::get( retTy, { IGM.Int8PtrTy }, /*vararg*/ false); auto layoutFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_get_arg_layout", IGM.getModule()); layoutFn->setAttributes(IGM.constructInitialAttributes()); layoutFn->setCallingConv(IGM.SwiftCC); { IRGenFunction IGF(IGM, layoutFn); if (IGM.DebugInfo) IGM.DebugInfo->emitArtificialFunction(IGF, layoutFn); // Unmarshal the generic environment from the argument buffer. auto parameters = IGF.collectParameters(); auto args = parameters.claimNext(); if (genericEnv) { bindFromGenericRequirementsBuffer( IGF, requirements, Address(args, IGM.Int8Ty, IGF.IGM.getPointerAlignment()), MetadataState::Complete, genericEnv->getForwardingSubstitutionMap()); } // Run through the captured index types to determine the size and alignment // needed. Start with pointer alignment for the generic environment. llvm::Value *size = llvm::ConstantInt::get(IGM.SizeTy, 0); llvm::Value *alignMask = llvm::ConstantInt::get(IGM.SizeTy, 0); for (auto &index : component.getArguments()) { auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), index.LoweredType) : index.LoweredType; auto &ti = IGM.getTypeInfo(ty); auto indexSize = ti.getSize(IGF, ty); auto indexAlign = ti.getAlignmentMask(IGF, ty); auto notIndexAlign = IGF.Builder.CreateNot(indexAlign); size = IGF.Builder.CreateAdd(size, indexAlign); size = IGF.Builder.CreateAnd(size, notIndexAlign); size = IGF.Builder.CreateAdd(size, indexSize); alignMask = IGF.Builder.CreateOr(alignMask, indexAlign); } // If there's generic environment to capture, then it's stored as a block // of pointer-aligned words after the captured values. auto genericsSize = llvm::ConstantInt::get(IGM.SizeTy, IGM.getPointerSize().getValue() * requirements.size()); auto genericsAlign = llvm::ConstantInt::get(IGM.SizeTy, IGM.getPointerAlignment().getValue() - 1); auto notGenericsAlign = llvm::ConstantExpr::getNot(genericsAlign); size = IGF.Builder.CreateAdd(size, genericsAlign); size = IGF.Builder.CreateAnd(size, notGenericsAlign); size = IGF.Builder.CreateAdd(size, genericsSize); alignMask = IGF.Builder.CreateOr(alignMask, genericsAlign); llvm::Value *retValue = IGF.Builder.CreateInsertValue( llvm::UndefValue::get(retTy), size, 0); retValue = IGF.Builder.CreateInsertValue( retValue, alignMask, 1); IGF.Builder.CreateRet(retValue); } return layoutFn; } static llvm::Constant * getWitnessTableForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, GenericEnvironment *genericEnv, ArrayRef requirements) { // If the only thing we're capturing is generic environment, then we can // use a prefab witness table from the runtime. A null reference will be // filled in by the runtime. if (component.getArguments().empty()) { return nullptr; } // Are the index values trivial? bool isTrivial = true; for (auto &component : component.getArguments()) { auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), component.LoweredType) : component.LoweredType; auto &ti = IGM.getTypeInfo(ty); isTrivial &= ti.isTriviallyDestroyable(ResilienceExpansion::Minimal); } llvm::Constant *destroy = nullptr; llvm::Constant *copy; if (isTrivial) { // We can use prefab witnesses for handling trivial copying and destruction. // A null destructor witness signals that the payload is trivial. copy = IGM.getCopyKeyPathTrivialIndicesFn(); } else { // Generate a destructor for this set of indices. { auto destroyType = llvm::FunctionType::get(IGM.VoidTy, {IGM.Int8PtrTy, IGM.SizeTy}, /*vararg*/ false); auto destroyFn = llvm::Function::Create(destroyType, llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule()); destroy = destroyFn; destroyFn->setAttributes(IGM.constructInitialAttributes()); destroyFn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, destroyFn); if (IGM.DebugInfo) IGM.DebugInfo->emitArtificialFunction(IGF, destroyFn); auto params = IGF.collectParameters(); auto componentArgsBuf = params.claimNext(); auto componentArgsBufSize = params.claimNext(); bindPolymorphicArgumentsFromComponentIndices( IGF, genericEnv, requirements, componentArgsBuf, componentArgsBufSize, !component.getArguments().empty()); llvm::Value *offset = nullptr; for (auto &component : component.getArguments()) { auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), component.LoweredType) : component.LoweredType; auto &ti = IGM.getTypeInfo(ty); if (offset) { auto align = ti.getAlignmentMask(IGF, ty); auto notAlign = IGF.Builder.CreateNot(align); offset = IGF.Builder.CreateAdd(offset, align); offset = IGF.Builder.CreateAnd(offset, notAlign); } else { offset = llvm::ConstantInt::get(IGM.SizeTy, 0); } auto elt = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, componentArgsBuf, offset); auto eltAddr = ti.getAddressForPointer( IGF.Builder.CreateBitCast(elt, ti.getStorageType()->getPointerTo())); ti.destroy(IGF, eltAddr, ty, true /*witness table: need it to be fast*/); auto size = ti.getSize(IGF, ty); offset = IGF.Builder.CreateAdd(offset, size); } IGF.Builder.CreateRetVoid(); } // Generate a copier for this set of indices. { auto copyType = llvm::FunctionType::get(IGM.VoidTy, {IGM.Int8PtrTy, IGM.Int8PtrTy, IGM.SizeTy}, /*vararg*/ false); auto copyFn = llvm::Function::Create(copyType, llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule()); copy = copyFn; copyFn->setAttributes(IGM.constructInitialAttributes()); copyFn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, copyFn); if (IGM.DebugInfo) IGM.DebugInfo->emitArtificialFunction(IGF, copyFn); auto params = IGF.collectParameters(); auto sourceArgsBuf = params.claimNext(); auto destArgsBuf = params.claimNext(); auto componentArgsBufSize = params.claimNext(); bindPolymorphicArgumentsFromComponentIndices( IGF, genericEnv, requirements, sourceArgsBuf, componentArgsBufSize, !component.getArguments().empty()); // Copy over the index values. llvm::Value *offset = nullptr; for (auto &component : component.getArguments()) { auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), component.LoweredType) : component.LoweredType; auto &ti = IGM.getTypeInfo(ty); if (offset) { auto align = ti.getAlignmentMask(IGF, ty); auto notAlign = IGF.Builder.CreateNot(align); offset = IGF.Builder.CreateAdd(offset, align); offset = IGF.Builder.CreateAnd(offset, notAlign); } else { offset = llvm::ConstantInt::get(IGM.SizeTy, 0); } auto sourceElt = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, sourceArgsBuf, offset); auto destElt = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, destArgsBuf, offset); auto sourceEltAddr = ti.getAddressForPointer( IGF.Builder.CreateBitCast(sourceElt, ti.getStorageType()->getPointerTo())); auto destEltAddr = ti.getAddressForPointer( IGF.Builder.CreateBitCast(destElt, ti.getStorageType()->getPointerTo())); ti.initializeWithCopy(IGF, destEltAddr, sourceEltAddr, ty, false); auto size = ti.getSize(IGF, ty); offset = IGF.Builder.CreateAdd(offset, size); } // Copy over the generic environment. if (genericEnv) { auto envAlignMask = llvm::ConstantInt::get(IGM.SizeTy, IGM.getPointerAlignment().getMaskValue()); auto notAlignMask = IGF.Builder.CreateNot(envAlignMask); offset = IGF.Builder.CreateAdd(offset, envAlignMask); offset = IGF.Builder.CreateAnd(offset, notAlignMask); auto sourceEnv = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, sourceArgsBuf, offset); auto destEnv = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, destArgsBuf, offset); auto align = IGM.getPointerAlignment().getValue(); IGF.Builder.CreateMemCpy(destEnv, llvm::MaybeAlign(align), sourceEnv, llvm::MaybeAlign(align), IGM.getPointerSize().getValue() * requirements.size()); } IGF.Builder.CreateRetVoid(); } } auto equals = getAccessorForComputedComponent(IGM, component, Equals); auto hash = getAccessorForComputedComponent(IGM, component, Hash); ConstantInitBuilder builder(IGM); ConstantStructBuilder fields = builder.beginStruct(); auto schemaKeyPath = IGM.getOptions().PointerAuth.KeyPaths; if (destroy) fields.addSignedPointer(destroy, schemaKeyPath, PointerAuthEntity::Special::KeyPathDestroy); else fields.addNullPointer(IGM.FunctionPtrTy); fields.addSignedPointer(copy, schemaKeyPath, PointerAuthEntity::Special::KeyPathCopy); fields.addSignedPointer(equals, schemaKeyPath, PointerAuthEntity::Special::KeyPathEquals); fields.addSignedPointer(hash, schemaKeyPath, PointerAuthEntity::Special::KeyPathHash); return fields.finishAndCreateGlobal( "keypath_witnesses", IGM.getPointerAlignment(), /*constant*/ true, llvm::GlobalVariable::PrivateLinkage); } /// Information about each index operand for a key path pattern that is used /// to lay out and consume the argument packet. struct KeyPathIndexOperand { SILType LoweredType; const KeyPathPatternComponent *LastUser; }; static llvm::Function * getInitializerForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, ArrayRef operands, GenericEnvironment *genericEnv, ArrayRef requirements) { auto fnTy = llvm::FunctionType::get(IGM.VoidTy, { /*src*/ IGM.Int8PtrTy, /*dest*/ IGM.Int8PtrTy }, /*vararg*/ false); auto initFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_arg_init", IGM.getModule()); initFn->setAttributes(IGM.constructInitialAttributes()); initFn->setCallingConv(IGM.SwiftCC); { IRGenFunction IGF(IGM, initFn); if (IGM.DebugInfo) IGM.DebugInfo->emitArtificialFunction(IGF, initFn); auto params = IGF.collectParameters(); // Pointer to the argument packet passed into swift_getKeyPath auto src = params.claimNext(); // Pointer to the destination component's argument buffer auto dest = params.claimNext(); SmallVector srcAddresses; int lastOperandNeeded = -1; for (auto &index : component.getArguments()) { lastOperandNeeded = std::max(lastOperandNeeded, (int)index.Operand); } llvm::Value *offset; if (genericEnv) { // We'll copy over the generic environment after we copy in the indexes. offset = llvm::ConstantInt::get(IGM.SizeTy, IGM.getPointerSize().getValue() * requirements.size()); // Bind the generic environment from the argument buffer. bindFromGenericRequirementsBuffer( IGF, requirements, Address(src, IGM.Int8Ty, IGF.IGM.getPointerAlignment()), MetadataState::Complete, genericEnv->getForwardingSubstitutionMap()); } else { offset = llvm::ConstantInt::get(IGM.SizeTy, 0); } // Figure out the offsets of the operands in the source buffer. for (int i = 0; i <= lastOperandNeeded; ++i) { auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), operands[i].LoweredType) : operands[i].LoweredType; auto &ti = IGM.getTypeInfo(ty); if (i != 0 || genericEnv) { auto alignMask = ti.getAlignmentMask(IGF, ty); auto notAlignMask = IGF.Builder.CreateNot(alignMask); offset = IGF.Builder.CreateAdd(offset, alignMask); offset = IGF.Builder.CreateAnd(offset, notAlignMask); } auto ptr = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, src, offset); auto addr = ti.getAddressForPointer(IGF.Builder.CreateBitCast( ptr, ti.getStorageType()->getPointerTo())); srcAddresses.push_back(addr); auto size = ti.getSize(IGF, ty); offset = IGF.Builder.CreateAdd(offset, size); } offset = llvm::ConstantInt::get(IGM.SizeTy, 0); // Transfer the operands we want into the destination buffer. for (unsigned i : indices(component.getArguments())) { auto &index = component.getArguments()[i]; auto ty = genericEnv ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), index.LoweredType) : index.LoweredType; auto &ti = IGM.getTypeInfo(ty); if (i != 0) { auto alignMask = ti.getAlignmentMask(IGF, ty); auto notAlignMask = IGF.Builder.CreateNot(alignMask); offset = IGF.Builder.CreateAdd(offset, alignMask); offset = IGF.Builder.CreateAnd(offset, notAlignMask); } auto ptr = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, dest, offset); auto destAddr = ti.getAddressForPointer(IGF.Builder.CreateBitCast( ptr, ti.getStorageType()->getPointerTo())); // The last component using an operand can move the value out of the // buffer. if (&component == operands[index.Operand].LastUser) { ti.initializeWithTake(IGF, destAddr, srcAddresses[index.Operand], ty, false, /*zeroizeIfSensitive=*/ true); } else { ti.initializeWithCopy(IGF, destAddr, srcAddresses[index.Operand], ty, false); } auto size = ti.getSize(IGF, ty); offset = IGF.Builder.CreateAdd(offset, size); } // Transfer the generic environment. // External components don't need to store the key path environment (and // can't), since they need to already have enough information to function // independently of any context using the component. if (genericEnv) { auto destGenericEnv = dest; if (!component.getArguments().empty()) { auto genericEnvAlignMask = llvm::ConstantInt::get(IGM.SizeTy, IGM.getPointerAlignment().getMaskValue()); auto notGenericEnvAlignMask = IGF.Builder.CreateNot(genericEnvAlignMask); offset = IGF.Builder.CreateAdd(offset, genericEnvAlignMask); offset = IGF.Builder.CreateAnd(offset, notGenericEnvAlignMask); destGenericEnv = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, dest, offset); } auto align = IGM.getPointerAlignment().getValue(); IGF.Builder.CreateMemCpy( destGenericEnv, llvm::MaybeAlign(align), src, llvm::MaybeAlign(align), IGM.getPointerSize().getValue() * requirements.size()); } IGF.Builder.CreateRetVoid(); } return initFn; } static llvm::Constant * emitMetadataTypeRefForKeyPath(IRGenModule &IGM, CanType type, CanGenericSignature sig) { // Produce a mangled name for the type. auto constant = IGM.getTypeRef(type, sig, MangledTypeRefRole::Metadata).first; // Mask the bottom bit to tell the key path runtime this is a mangled name // rather than a direct reference. auto bitConstant = llvm::ConstantInt::get(IGM.IntPtrTy, 1); return llvm::ConstantExpr::getGetElementPtr(IGM.Int8Ty, constant, bitConstant); } static unsigned getClassFieldIndex(ClassDecl *classDecl, VarDecl *property) { SmallVector superclasses; for (auto *superDecl = classDecl; superDecl != nullptr; superDecl = superDecl->getSuperclassDecl()) { superclasses.push_back(superDecl); } std::reverse(superclasses.begin(), superclasses.end()); unsigned index = 0; for (auto *superDecl : superclasses) { for (auto *other : superDecl->getStoredProperties()) { if (other == property) return index; ++index; } } llvm_unreachable("Did not find stored property in class"); } static void emitKeyPathComponent(IRGenModule &IGM, ConstantStructBuilder &fields, const KeyPathPatternComponent &component, bool isInstantiableOnce, GenericEnvironment *genericEnv, ArrayRef requirements, CanType baseTy, ArrayRef operands, bool hasSubscriptIndices) { assert(fields.getNextOffsetFromGlobal() % Alignment(4) == Size(0) && "must be 32-bit-aligned here"); SILType loweredBaseTy; loweredBaseTy = IGM.getLoweredType(AbstractionPattern::getOpaque(), baseTy->getWithoutSpecifierType()); // TODO: Eliminate GenericContextScope entirely GenericContextScope scope( IGM, genericEnv ? genericEnv->getGenericSignature().getCanonicalSignature() : nullptr); switch (auto kind = component.getKind()) { case KeyPathPatternComponent::Kind::StoredProperty: { auto property = cast(component.getStoredPropertyDecl()); auto addFixedOffset = [&](bool isStruct, bool isLet, llvm::Constant *offset) { if (auto offsetInt = dyn_cast_or_null(offset)) { auto offsetValue = offsetInt->getValue().getZExtValue(); if (KeyPathComponentHeader::offsetCanBeInline(offsetValue)) { auto header = isStruct ? KeyPathComponentHeader ::forStructComponentWithInlineOffset(isLet, offsetValue) : KeyPathComponentHeader ::forClassComponentWithInlineOffset(isLet, offsetValue); fields.addInt32(header.getData()); return; } } auto header = isStruct ? KeyPathComponentHeader::forStructComponentWithOutOfLineOffset(isLet) : KeyPathComponentHeader::forClassComponentWithOutOfLineOffset(isLet); fields.addInt32(header.getData()); fields.add(llvm::ConstantExpr::getTruncOrBitCast(offset, IGM.Int32Ty)); }; // For a struct stored property, we may know the fixed offset of the field, // or we may need to fetch it out of the type's metadata at instantiation // time. if (auto theStruct = loweredBaseTy.getStructOrBoundGenericStruct()) { if (auto offset = emitPhysicalStructMemberFixedOffset(IGM, loweredBaseTy, property)) { // We have a known constant fixed offset. addFixedOffset(/*struct*/ true, property->isLet(), offset); break; } // If the offset isn't fixed, try instead to get the field offset out // of the type metadata at instantiation time. auto &metadataLayout = IGM.getMetadataLayout(theStruct); auto fieldOffset = metadataLayout.getStaticFieldOffset(property); auto header = KeyPathComponentHeader ::forStructComponentWithUnresolvedFieldOffset(property->isLet()); fields.addInt32(header.getData()); fields.addInt32(fieldOffset.getValue()); break; } auto *classDecl = baseTy->getClassOrBoundGenericClass(); auto loweredClassTy = loweredBaseTy; // Recover class decl from superclass constraint if (!classDecl && genericEnv) { auto ty = genericEnv->mapTypeIntoContext(baseTy)->getCanonicalType(); auto archetype = dyn_cast(ty); if (archetype && archetype->requiresClass()) { auto superClassTy = ty->getSuperclass(false)->getCanonicalType(); classDecl = superClassTy->getClassOrBoundGenericClass(); loweredClassTy = IGM.getLoweredType(AbstractionPattern::getOpaque(), superClassTy->getWithoutSpecifierType()); } } // For a class, we may know the fixed offset of a field at compile time, // or we may need to fetch it at instantiation time. Depending on the // ObjC-ness and resilience of the class hierarchy, there might be a few // different ways we need to go about this. if (loweredClassTy.getClassOrBoundGenericClass()) { // Use the property's class type to determine the field access. auto propertyBaseDecl = property->getDeclContext()->getSelfClassDecl(); auto currentBaseTy = loweredClassTy.getASTType()->getSuperclassForDecl(propertyBaseDecl); assert(currentBaseTy->getClassOrBoundGenericClass() == propertyBaseDecl); loweredClassTy = IGM.getLoweredType(AbstractionPattern::getOpaque(), currentBaseTy); auto loweredBaseContextTy = SILType::getPrimitiveObjectType(loweredClassTy.getASTType()); if (!loweredClassTy.getASTType()->hasArchetype()) loweredBaseContextTy = SILType::getPrimitiveObjectType( GenericEnvironment::mapTypeIntoContext(genericEnv, loweredClassTy.getASTType()) ->getCanonicalType()); switch (getClassFieldAccess(IGM, loweredBaseContextTy, property)) { case FieldAccess::ConstantDirect: { // Known compile-time constant field offset. auto offset = tryEmitConstantClassFragilePhysicalMemberOffset( IGM, loweredClassTy, property); assert(offset && "no constant offset for ConstantDirect field?!"); addFixedOffset(/*struct*/ false, property->isLet(), offset); break; } case FieldAccess::NonConstantDirect: { // A constant offset that's determined at class realization time. // We have to load the offset from a global ivar. // // This means the field offset is constant at runtime, but is not known // at compile time. auto header = KeyPathComponentHeader ::forClassComponentWithUnresolvedIndirectOffset(property->isLet()); fields.addInt32(header.getData()); auto offsetRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forFieldOffset(property)); fields.addRelativeAddress(offsetRef); break; } case FieldAccess::ConstantIndirect: { // An offset that depends on the instance's generic parameterization, // but whose field offset is at a known metadata offset. auto header = KeyPathComponentHeader ::forClassComponentWithUnresolvedFieldOffset(property->isLet()); fields.addInt32(header.getData()); // FIXME: This doesn't support classes with resilient ancestry, because // the offset into the metadata is itself not constant. // // SILGen emits the descriptor as a computed property in this case. auto fieldOffset = getClassFieldOffsetOffset( IGM, loweredClassTy.getClassOrBoundGenericClass(), property); fields.addInt32(fieldOffset.getValue()); break; } } break; } llvm_unreachable("not struct or class"); } case KeyPathPatternComponent::Kind::GettableProperty: case KeyPathPatternComponent::Kind::SettableProperty: case KeyPathPatternComponent::Kind::Method: { // If the component references an external property, encode that in a // header before the local attempt header, so that we can consult the // external descriptor at instantiation time. // // Note that when compiling inlinable functions, we can have external // declarations that point within the same module. Just ignore those. auto externalDecl = component.getExternalDecl(); if (externalDecl && externalDecl->getModuleContext() != IGM.getSwiftModule()) { SmallVector externalSubArgs; auto componentSig = externalDecl->getInnermostDeclContext() ->getGenericSignatureOfContext(); auto componentCanSig = componentSig.getCanonicalSignature(); auto subs = component.getExternalSubstitutions(); if (!subs.empty()) { enumerateGenericSignatureRequirements( componentCanSig, [&](GenericRequirement reqt) { auto substType = reqt.getTypeParameter().subst(subs)->getCanonicalType(); // FIXME: This seems wrong. We used to just mangle opened archetypes as // their interface type. Let's make that explicit now. substType = substType .transformRec([](Type t) -> std::optional { if (auto *openedExistential = t->getAs()) { auto &ctx = openedExistential->getASTContext(); return ctx.TheSelfType; } return std::nullopt; }) ->getCanonicalType(); if (reqt.isAnyMetadata()) { // Type requirement. externalSubArgs.push_back(emitMetadataTypeRefForKeyPath( IGM, substType, componentCanSig)); } else { assert(reqt.isAnyWitnessTable()); // Protocol requirement. auto conformance = subs.lookupConformance( reqt.getTypeParameter()->getCanonicalType(), reqt.getProtocol()); externalSubArgs.push_back(IGM.emitWitnessTableRefString( substType, conformance, genericEnv ? genericEnv->getGenericSignature() : componentCanSig, /*shouldSetLowBit*/ true)); } }); } fields.addInt32( KeyPathComponentHeader::forExternalComponent(externalSubArgs.size()) .getData()); if (auto *decl = dyn_cast(externalDecl)) { auto descriptor = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forPropertyDescriptor(decl)); fields.addRelativeAddress(descriptor); } for (auto *arg : externalSubArgs) fields.addRelativeAddress(arg); } // Encode the settability. bool settable = kind == KeyPathPatternComponent::Kind::SettableProperty; bool mutating = settable && component.isComputedSettablePropertyMutating(); KeyPathComponentHeader::ComputedPropertyKind componentKind; if (settable) { componentKind = mutating ? KeyPathComponentHeader::SettableMutating : KeyPathComponentHeader::SettableNonmutating; } else { componentKind = KeyPathComponentHeader::GetOnly; } // Lower the id reference. auto id = component.getComputedPropertyId(); KeyPathComponentHeader::ComputedPropertyIDKind idKind; llvm::Constant *idValue; KeyPathComponentHeader::ComputedPropertyIDResolution idResolution; switch (id.getKind()) { case KeyPathPatternComponent::ComputedPropertyId::Function: { idKind = KeyPathComponentHeader::Pointer; // FIXME: Does this need to be signed? auto idRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forSILFunction(id.getFunction())); idValue = idRef.getValue(); // If we got an indirect reference, we'll need to resolve it at // instantiation time. idResolution = idRef.isIndirect() ? KeyPathComponentHeader::IndirectPointer // Compute absolute reference from relative reference if target supports it. // Otherwise, embed absolute reference directly. : (IGM.getOptions().CompactAbsoluteFunctionPointer ? KeyPathComponentHeader::ResolvedAbsolute : KeyPathComponentHeader::Resolved); break; } case KeyPathPatternComponent::ComputedPropertyId::DeclRef: { auto declRef = id.getDeclRef(); // Foreign method refs identify using a selector // reference, which is doubly-indirected and filled in with a unique // pointer by dyld. if (declRef.isForeign) { assert(IGM.ObjCInterop && "foreign keypath component w/o objc interop?!"); idKind = KeyPathComponentHeader::Pointer; // FIXME: In non-JIT mode, ideally we would just refer to the selector // reference variable here with an indirectpointer resolution, // but ld64 section coalescing on the __objc_sel section can break // relative references (and on some platforms, mach-o just doesn't // support the necessary relocations). // As a workaround, generate a stub function to resolve the selector. // // Note that we'd need to do this anyway in JIT mode because we would // need to unique the selector at runtime anyway. auto selectorName = IGM.getObjCSelectorName(declRef); SmallString<32> fnName; fnName.append("keypath_get_selector_"); fnName.append(selectorName); auto fn = IGM.getOrCreateHelperFunction(fnName, IGM.Int8PtrTy, {IGM.Int8PtrTy}, [&selectorName](IRGenFunction &subIGF) { auto selectorValue = subIGF.emitObjCSelectorRefLoad(selectorName); subIGF.Builder.CreateRet(selectorValue); }); idValue = fn; idResolution = KeyPathComponentHeader::FunctionCall; } else { if (auto overridden = declRef.getOverriddenVTableEntry()) declRef = overridden; if (auto overridden = declRef.getOverriddenWitnessTableEntry()) declRef = overridden; auto dc = declRef.getDecl()->getDeclContext(); // We can use a method descriptor if we have a class or resilient // protocol. if (isa(dc) || IGM.isResilient(cast(dc), ResilienceExpansion::Minimal)) { idKind = KeyPathComponentHeader::Pointer; auto idRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forMethodDescriptor(declRef)); idValue = idRef.getValue(); idResolution = idRef.isIndirect() ? KeyPathComponentHeader::IndirectPointer : KeyPathComponentHeader::Resolved; break; } idKind = KeyPathComponentHeader::VTableOffset; auto methodProto = cast(dc); auto &protoInfo = IGM.getProtocolInfo(methodProto, ProtocolInfoKind::Full); auto index = protoInfo.getFunctionIndex(declRef); idValue = llvm::ConstantInt::get(IGM.SizeTy, -index.getValue()); idResolution = KeyPathComponentHeader::Resolved; } break; } case KeyPathPatternComponent::ComputedPropertyId::Property: // Use the index of the stored property within the aggregate to key // the property. auto property = id.getProperty(); idKind = KeyPathComponentHeader::StoredPropertyIndex; auto *classDecl = baseTy->getClassOrBoundGenericClass(); auto loweredClassTy = loweredBaseTy; // Recover class decl from superclass constraint if (!classDecl && genericEnv) { auto ty = genericEnv->mapTypeIntoContext(baseTy)->getCanonicalType(); auto archetype = dyn_cast(ty); if (archetype && archetype->requiresClass()) { auto superClassTy = ty->getSuperclass(false)->getCanonicalType(); classDecl = superClassTy->getClassOrBoundGenericClass(); loweredClassTy = IGM.getLoweredType(AbstractionPattern::getOpaque(), superClassTy->getWithoutSpecifierType()); } } if (auto struc = baseTy->getStructOrBoundGenericStruct()) { // Scan the stored properties of the struct to find the index. We should // only ever use a struct field as a uniquing key from inside the // struct's own module, so this is OK. idResolution = KeyPathComponentHeader::Resolved; std::optional structIdx; unsigned i = 0; for (auto storedProp : struc->getStoredProperties()) { if (storedProp == property) { structIdx = i; break; } ++i; } assert(structIdx && "not a stored property of the struct?!"); idValue = llvm::ConstantInt::get(IGM.SizeTy, structIdx.value()); } else if (classDecl) { // TODO: This field index would require runtime resolution with Swift // native class resilience. We never directly access ObjC-imported // ivars so we can disregard ObjC ivar resilience for this computation // and start counting at the Swift native root. if (loweredClassTy.getASTType()->hasTypeParameter()) loweredClassTy = SILType::getPrimitiveObjectType( GenericEnvironment::mapTypeIntoContext( genericEnv, loweredClassTy.getASTType()) ->getCanonicalType()); switch (getClassFieldAccess(IGM, loweredClassTy, property)) { case FieldAccess::ConstantDirect: case FieldAccess::ConstantIndirect: case FieldAccess::NonConstantDirect: idResolution = KeyPathComponentHeader::Resolved; idValue = llvm::ConstantInt::get(IGM.SizeTy, getClassFieldIndex(classDecl, property)); break; } } else { llvm_unreachable("neither struct nor class"); } break; } auto header = KeyPathComponentHeader::forComputedProperty(componentKind, idKind, !isInstantiableOnce, idResolution); fields.addInt32(header.getData()); switch (idKind) { case KeyPathComponentHeader::Pointer: // Use a relative offset to the referent if value is not absolute. if (idResolution == KeyPathComponentHeader::ResolvedAbsolute) { fields.add(idValue); } else { fields.addRelativeAddress(idValue); } break; case KeyPathComponentHeader::VTableOffset: case KeyPathComponentHeader::StoredPropertyIndex: // Store the offset as an i32. fields.add(llvm::ConstantExpr::getTruncOrBitCast(idValue, IGM.Int32Ty)); break; } // Push the accessors, possibly thunked to marshal generic environment. fields.addCompactFunctionReference( getAccessorForComputedComponent(IGM, component, Getter)); if (settable) fields.addCompactFunctionReference( getAccessorForComputedComponent(IGM, component, Setter)); if (!isInstantiableOnce) { // If there's generic context or subscript indexes, embed as // arguments in the component. Thunk the SIL-level accessors to give the // runtime implementation a polymorphically-callable interface. fields.addCompactFunctionReference( getLayoutFunctionForComputedComponent(IGM, component, genericEnv, requirements)); // Set up a "witness table" for the component that handles copying, // destroying, equating, and hashing the captured contents of the // component. if (auto witnessTable = getWitnessTableForComputedComponent(IGM, component, genericEnv, requirements)) { fields.addRelativeAddress(witnessTable); } else { // If there are only generic parameters, we can use a prefab witness // table from the runtime. Leaving a null reference here will let // the runtime fill it in. fields.addInt32(0); } // Add an initializer function that copies generic arguments out of the // pattern argument buffer into the instantiated object. fields.addCompactFunctionReference( getInitializerForComputedComponent(IGM, component, operands, genericEnv, requirements)); } break; } case KeyPathPatternComponent::Kind::OptionalChain: fields.addInt32(KeyPathComponentHeader::forOptionalChain().getData()); break; case KeyPathPatternComponent::Kind::OptionalForce: fields.addInt32(KeyPathComponentHeader::forOptionalForce().getData()); break; case KeyPathPatternComponent::Kind::OptionalWrap: fields.addInt32(KeyPathComponentHeader::forOptionalWrap().getData()); break; case KeyPathPatternComponent::Kind::TupleElement: assert(baseTy->is() && "not a tuple"); SILType loweredTy = IGM.getLoweredType(AbstractionPattern::getOpaque(), baseTy); // Tuple with fixed layout // // This code is ALSO executed in the case of a tuple with dynamic layout, // (see below) but only if `component.getTupleIndex()` is 0 - in that case // the compiler knows that the tuple element is always at offset 0. // TODO: If this is behavior is not desired we should find a way to skip to // the next section of code e.g. check if baseTy has archetypes? if (auto offset = getFixedTupleElementOffset(IGM, loweredTy, component.getTupleIndex())) { auto header = KeyPathComponentHeader ::forStructComponentWithInlineOffset(/*isLet*/ false, offset->getValue()); fields.addInt32(header.getData()); break; } // Tuple with dynamic layout auto elementOffset = getStaticTupleElementOffset(IGM, loweredTy, component.getTupleIndex()); auto header = KeyPathComponentHeader ::forStructComponentWithUnresolvedFieldOffset(/*isLet*/ false); fields.addInt32(header.getData()); fields.addInt32(elementOffset.getValue()); break; llvm_unreachable("could not get tuple element offset"); } } llvm::Constant * IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, SILLocation diagLoc) { // See if we already emitted this. auto found = KeyPathPatterns.find(pattern); if (found != KeyPathPatterns.end()) return found->second; // Gather type arguments from the root and leaf types of the key path. auto rootTy = pattern->getRootType(); auto valueTy = pattern->getValueType(); // Check for parameterization, whether by subscript indexes or by the generic // environment. If there isn't any, we can instantiate the pattern in-place. bool isInstantiableOnce = pattern->getNumOperands() == 0 && !pattern->getGenericSignature(); // Collect the required parameters for the keypath's generic environment. SmallVector requirements; auto *genericEnv = pattern->getGenericSignature().getGenericEnvironment(); enumerateGenericSignatureRequirements(pattern->getGenericSignature(), [&](GenericRequirement reqt) { requirements.push_back(reqt); }); // Start building the key path pattern. ConstantInitBuilder builder(*this); ConstantStructBuilder fields = builder.beginStruct(); fields.setPacked(true); // If the pattern has no parameterization, add a pointer to a cache variable // that can be used for the one-time initialization of the key path. if (isInstantiableOnce) { auto onceVar = new llvm::GlobalVariable(Module, OnceTy, /*constant*/ false, llvm::GlobalValue::PrivateLinkage, llvm::ConstantInt::get(OnceTy, 0), "keypath_once"); onceVar->setAlignment(llvm::MaybeAlign(getPointerAlignment().getValue())); fields.addRelativeAddress(onceVar); } else { fields.addInt32(0); } // Add the generic environment. fields.addRelativeAddressOrNull( getAddrOfGenericEnvironment(pattern->getGenericSignature())); // Store type references for the root and leaf. fields.addRelativeAddress( emitMetadataTypeRefForKeyPath(*this, rootTy, pattern->getGenericSignature())); fields.addRelativeAddress( emitMetadataTypeRefForKeyPath(*this, valueTy, pattern->getGenericSignature())); // Add a pointer to the ObjC KVC compatibility string, if there is one, or // null otherwise. if (!pattern->getObjCString().empty()) { auto objcString = getAddrOfGlobalString(pattern->getObjCString(), /*relatively addressed*/ true); fields.addRelativeAddress(objcString); } else { fields.addInt32(0); } // Leave a placeholder for the buffer header, since we need to know the full // buffer size to fill it in. auto headerPlaceholder = fields.addPlaceholderWithSize(Int32Ty); auto startOfKeyPathBuffer = fields.getNextOffsetFromGlobal(); // Build out the components. auto baseTy = rootTy; // Collect the order and types of any captured index operands, which will // determine the layout of the buffer that gets passed to the initializer // for each component. SmallVector operands; operands.resize(pattern->getNumOperands()); for (auto &component : pattern->getComponents()) { switch (component.getKind()) { case KeyPathPatternComponent::Kind::GettableProperty: case KeyPathPatternComponent::Kind::SettableProperty: case KeyPathPatternComponent::Kind::Method: for (auto &index : component.getArguments()) { operands[index.Operand].LoweredType = index.LoweredType; operands[index.Operand].LastUser = &component; } break; case KeyPathPatternComponent::Kind::StoredProperty: case KeyPathPatternComponent::Kind::OptionalChain: case KeyPathPatternComponent::Kind::OptionalForce: case KeyPathPatternComponent::Kind::OptionalWrap: case KeyPathPatternComponent::Kind::TupleElement: break; } } for (unsigned i : indices(pattern->getComponents())) { auto &component = pattern->getComponents()[i]; emitKeyPathComponent(*this, fields, component, isInstantiableOnce, genericEnv, requirements, baseTy, operands, !component.getArguments().empty()); // For all but the last component, we pack in the type of the component. if (i + 1 != pattern->getComponents().size()) { fields.addRelativeAddress( emitMetadataTypeRefForKeyPath(*this, component.getComponentType(), pattern->getGenericSignature())); } baseTy = component.getComponentType(); } // Save the total size of the buffer. Size componentSize = fields.getNextOffsetFromGlobal() - startOfKeyPathBuffer; // We now have enough info to build the header. KeyPathBufferHeader header(componentSize.getValue(), isInstantiableOnce, /*reference prefix*/ false); // Add the header, followed by the components. fields.fillPlaceholder(headerPlaceholder, llvm::ConstantInt::get(Int32Ty, header.getData())); // Create the global variable. // TODO: The pattern could be immutable if // it isn't instantiable in place, and if we made the type metadata accessor // references private, it could go in true-const memory. auto patternVar = fields.finishAndCreateGlobal("keypath", getPointerAlignment(), /*constant*/ false, llvm::GlobalVariable::PrivateLinkage); setTrueConstGlobal(patternVar); KeyPathPatterns.insert({pattern, patternVar}); return patternVar; } void IRGenModule::emitSILProperty(SILProperty *prop) { if (prop->isTrivial()) { ++NumTrivialPropertyDescriptors; // All trivial property descriptors can share a single definition in the // translation unit. if (!TheTrivialPropertyDescriptor) { // Emit a definition if we don't have one yet. ConstantInitBuilder builder(*this); ConstantStructBuilder fields = builder.beginStruct(); fields.addInt32( _SwiftKeyPathComponentHeader_TrivialPropertyDescriptorMarker); auto var = cast( getAddrOfPropertyDescriptor(prop->getDecl(), fields.finishAndCreateFuture())); var->setConstant(true); var->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); var->setAlignment(llvm::MaybeAlign(4)); TheTrivialPropertyDescriptor = var; } else { auto entity = LinkEntity::forPropertyDescriptor(prop->getDecl()); auto linkInfo = LinkInfo::get(*this, entity, ForDefinition); auto *GA = llvm::GlobalAlias::create(linkInfo.getLinkage(), linkInfo.getName(), TheTrivialPropertyDescriptor); ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), IRGen.Opts.InternalizeSymbols ? llvm::GlobalValue::DefaultStorageClass : llvm::GlobalValue::DLLExportStorageClass}) .to(GA, linkInfo.isForDefinition()); } return; } ++NumNonTrivialPropertyDescriptors; ConstantInitBuilder builder(*this); ConstantStructBuilder fields = builder.beginStruct(); fields.setPacked(true); bool hasSubscriptIndices = false; bool isInstantiableInPlace = true; if (prop->getDecl()->getInnermostDeclContext()->isGenericContext()) { isInstantiableInPlace = false; } if (auto subscript = dyn_cast(prop->getDecl())) { hasSubscriptIndices = subscript->getIndices()->size() != 0; isInstantiableInPlace &= !hasSubscriptIndices; } auto genericEnv = prop->getDecl()->getInnermostDeclContext() ->getGenericEnvironmentOfContext(); SmallVector requirements; CanGenericSignature genericSig; if (genericEnv) { genericSig = prop->getDecl() ->getInnermostDeclContext() ->getGenericSignatureOfContext() .getCanonicalSignature(); enumerateGenericSignatureRequirements(genericSig, [&](GenericRequirement reqt) { requirements.push_back(reqt); }); } emitKeyPathComponent(*this, fields, *prop->getComponent(), isInstantiableInPlace, genericEnv, requirements, prop->getDecl()->getInnermostDeclContext() ->getInnermostTypeContext() ->getSelfInterfaceType() ->getReducedType(genericSig), {}, hasSubscriptIndices); auto var = cast( getAddrOfPropertyDescriptor(prop->getDecl(), fields.finishAndCreateFuture())); var->setConstant(true); var->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); var->setAlignment(llvm::MaybeAlign(4)); } std::pair irgen::emitKeyPathArgument( IRGenFunction &IGF, SubstitutionMap subs, const CanGenericSignature &sig, ArrayRef indiceTypes, Explosion &indiceValues, std::optional &dynamicArgsBuf) { auto &IGM = IGF.IGM; if (subs.empty() && indiceTypes.empty()) { // No arguments necessary, so the argument ought to be ignored by any // callbacks in the pattern. assert(indiceTypes.empty() && "indices not implemented"); return std::make_pair(llvm::UndefValue::get(IGM.Int8PtrTy), llvm::ConstantInt::get(IGM.SizeTy, 0)); } SmallVector requirements; enumerateGenericSignatureRequirements( sig, [&](GenericRequirement reqt) { requirements.push_back(reqt); }); llvm::Value *argsBufSize = llvm::ConstantInt::get(IGM.SizeTy, 0); SmallVector operandOffsets; for (unsigned i : indices(indiceTypes)) { auto &indiceTy = indiceTypes[i]; auto &ti = IGF.getTypeInfo(indiceTy); if (i != 0) { auto alignMask = ti.getAlignmentMask(IGF, indiceTy); auto notAlignMask = IGF.Builder.CreateNot(alignMask); argsBufSize = IGF.Builder.CreateAdd(argsBufSize, alignMask); argsBufSize = IGF.Builder.CreateAnd(argsBufSize, notAlignMask); } operandOffsets.push_back(argsBufSize); auto size = ti.getSize(IGF, indiceTy); argsBufSize = IGF.Builder.CreateAdd(argsBufSize, size); } if (!subs.empty()) { argsBufSize = llvm::ConstantInt::get( IGM.SizeTy, IGM.getPointerSize().getValue() * requirements.size()); } dynamicArgsBuf = IGF.emitDynamicAlloca(IGM.Int8Ty, argsBufSize, Alignment(16)); Address argsBuf = dynamicArgsBuf->getAddress(); // Copy indices into the buffer. for (unsigned i : indices(indiceTypes)) { auto operandTy = indiceTypes[i]; auto &ti = IGF.getTypeInfo(operandTy); auto ptr = IGF.Builder.CreateInBoundsGEP(IGM.Int8Ty, argsBuf.getAddress(), operandOffsets[i]); auto addr = ti.getAddressForPointer( IGF.Builder.CreateBitCast(ptr, ti.getStorageType()->getPointerTo())); if (operandTy.isAddress()) { ti.initializeWithTake(IGF, addr, ti.getAddressForPointer(indiceValues.claimNext()), operandTy, false, /*zeroizeIfSensitive=*/ true); } else { cast(ti).initialize(IGF, indiceValues, addr, false); } } if (!subs.empty()) { emitInitOfGenericRequirementsBuffer(IGF, requirements, argsBuf, MetadataState::Complete, subs); } return std::make_pair(argsBuf.getAddress(), argsBufSize); }