@@ -2036,39 +2036,19 @@ namespace {
20362036 addGenericSignature ();
20372037 addUnderlyingTypeAndConformances ();
20382038 }
2039-
2040- void addUnderlyingTypeAndConformances () {
2041- auto sig = O->getOpaqueInterfaceGenericSignature ();
2042- auto contextSig = O->getGenericSignature ().getCanonicalSignature ();
2043- auto subs = *O->getUniqueUnderlyingTypeSubstitutions ();
20442039
2045- // Add the underlying types for each generic parameter.
2046- for (auto genericParam : O->getOpaqueGenericParams ()) {
2047- auto underlyingType = Type (genericParam).subst (subs)->getCanonicalType (sig);
2048- B.addRelativeAddress (
2049- IGM.getTypeRef (underlyingType, contextSig,
2050- MangledTypeRefRole::Metadata).first );
2040+ void addUnderlyingTypeAndConformances () {
2041+ for (unsigned index : indices (O->getOpaqueGenericParams ())) {
2042+ B.addRelativeAddress (getUnderlyingTypeRef (index));
20512043 }
20522044
2053- // Add witness tables for each of the conformance requirements.
2045+ auto sig = O-> getOpaqueInterfaceGenericSignature ();
20542046 for (const auto &req : sig.getRequirements ()) {
2055- auto proto = requiresWitnessTable (req);
2056- if (!proto)
2057- continue ;
2058-
2059- auto underlyingDependentType = req.getFirstType ()->getCanonicalType ();
2060- auto underlyingType = underlyingDependentType.subst (subs)
2061- ->getCanonicalType ();
2062- auto underlyingConformance =
2063- subs.lookupConformance (underlyingDependentType, proto);
2064- auto witnessTableRef = IGM.emitWitnessTableRefString (
2065- underlyingType, underlyingConformance,
2066- contextSig,
2067- /* setLowBit*/ false );
2068- B.addRelativeAddress (witnessTableRef);
2047+ if (auto *proto = requiresWitnessTable (req))
2048+ B.addRelativeAddress (getWitnessTableRef (req, proto));
20692049 }
20702050 }
2071-
2051+
20722052 bool isUniqueDescriptor () {
20732053 switch (LinkEntity::forOpaqueTypeDescriptor (O)
20742054 .getLinkage (NotForDefinition)) {
@@ -2144,6 +2124,326 @@ namespace {
21442124
21452125 return O->getOpaqueGenericParams ().size () + numWitnessTables;
21462126 }
2127+
2128+ private:
2129+ llvm::Constant *getUnderlyingTypeRef (unsigned opaqueParamIdx) const {
2130+
2131+ // If this opaque declaration has a unique set of substitutions,
2132+ // we can simply emit a direct type reference.
2133+ if (auto unique = O->getUniqueUnderlyingTypeSubstitutions ()) {
2134+ auto sig = O->getOpaqueInterfaceGenericSignature ();
2135+ auto contextSig = O->getGenericSignature ().getCanonicalSignature ();
2136+
2137+ auto *genericParam = O->getOpaqueGenericParams ()[opaqueParamIdx];
2138+ auto underlyingType =
2139+ Type (genericParam).subst (*unique)->getCanonicalType (sig);
2140+ return IGM
2141+ .getTypeRef (underlyingType, contextSig,
2142+ MangledTypeRefRole::Metadata)
2143+ .first ;
2144+ }
2145+
2146+ // Otherwise, we have to go through a metadata accessor to
2147+ // fetch underlying type at runtime.
2148+
2149+ // There are one or more underlying types with limited
2150+ // availability and one universally available one. This
2151+ // requires us to build a metadata accessor.
2152+ auto substitutionSet = O->getConditionallyAvailableSubstitutions ();
2153+ assert (!substitutionSet.empty ());
2154+
2155+ UnderlyingTypeAccessor accessor (IGM, O, opaqueParamIdx);
2156+ return accessor.emit (substitutionSet);
2157+ }
2158+
2159+ llvm::Constant *getWitnessTableRef (const Requirement &req,
2160+ ProtocolDecl *protocol) {
2161+ auto contextSig = O->getGenericSignature ().getCanonicalSignature ();
2162+ auto underlyingDependentType = req.getFirstType ()->getCanonicalType ();
2163+
2164+ if (auto unique = O->getUniqueUnderlyingTypeSubstitutions ()) {
2165+ auto underlyingType =
2166+ underlyingDependentType.subst (*unique)->getCanonicalType ();
2167+ auto underlyingConformance =
2168+ unique->lookupConformance (underlyingDependentType, protocol);
2169+
2170+ return IGM.emitWitnessTableRefString (underlyingType,
2171+ underlyingConformance, contextSig,
2172+ /* setLowBit*/ false );
2173+ }
2174+
2175+ WitnessTableAccessor accessor (IGM, O, req, protocol);
2176+ return accessor.emit (O->getConditionallyAvailableSubstitutions ());
2177+ }
2178+
2179+ class AbstractMetadataAccessor {
2180+ protected:
2181+ IRGenModule &IGM;
2182+
2183+ // / The opaque type declaration for this accessor.
2184+ OpaqueTypeDecl *O;
2185+
2186+ public:
2187+ AbstractMetadataAccessor (IRGenModule &IGM, OpaqueTypeDecl *O)
2188+ : IGM(IGM), O(O) {}
2189+
2190+ virtual ~AbstractMetadataAccessor () {}
2191+
2192+ // / The unique symbol this accessor would be reachable by at runtime.
2193+ virtual std::string getSymbol () const = 0;
2194+
2195+ // / The result type for this accessor. This type would have
2196+ // / to match a type produced by \c getResultValue.
2197+ virtual llvm::Type *getResultType () const = 0;
2198+
2199+ // / Produce a result value based on the given set of substitutions.
2200+ virtual llvm::Value *
2201+ getResultValue (IRGenFunction &IGF, GenericEnvironment *genericEnv,
2202+ SubstitutionMap substitutions) const = 0 ;
2203+
2204+ llvm::Constant *
2205+ emit (ArrayRef<OpaqueTypeDecl::ConditionallyAvailableSubstitutions *>
2206+ substitutionSet) {
2207+ auto getInt32Constant =
2208+ [&](Optional<unsigned > value) -> llvm::ConstantInt * {
2209+ return llvm::ConstantInt::get (IGM.Int32Ty , value.getValueOr (0 ));
2210+ };
2211+
2212+ auto symbol = getSymbol ();
2213+
2214+ auto *accessor = getAccessorFn (symbol);
2215+ {
2216+ IRGenFunction IGF (IGM, accessor);
2217+
2218+ if (IGM.DebugInfo )
2219+ IGM.DebugInfo ->emitArtificialFunction (IGF, accessor);
2220+
2221+ auto signature = O->getGenericSignature ().getCanonicalSignature ();
2222+ auto *genericEnv = signature.getGenericEnvironment ();
2223+
2224+ // Prepare contextual replacements.
2225+ {
2226+ SmallVector<GenericRequirement, 4 > requirements;
2227+
2228+ enumerateGenericSignatureRequirements (
2229+ signature,
2230+ [&](GenericRequirement req) { requirements.push_back (req); });
2231+
2232+ auto bindingsBufPtr = IGF.collectParameters ().claimNext ();
2233+
2234+ bindFromGenericRequirementsBuffer (
2235+ IGF, requirements,
2236+ Address (bindingsBufPtr, IGM.getPointerAlignment ()),
2237+ MetadataState::Complete, [&](CanType t) {
2238+ return genericEnv ? genericEnv->mapTypeIntoContext (t)
2239+ ->getCanonicalType ()
2240+ : t;
2241+ });
2242+ }
2243+
2244+ SmallVector<llvm::BasicBlock *, 4 > conditionalTypes;
2245+
2246+ // Pre-allocate a basic block per condition, so there it's
2247+ // possible to jump between conditions.
2248+ for (unsigned index : indices (substitutionSet)) {
2249+ conditionalTypes.push_back (
2250+ IGF.createBasicBlock ((index < substitutionSet.size () - 1 )
2251+ ? " conditional-" + llvm::utostr (index)
2252+ : " universal" ));
2253+ }
2254+
2255+ // Jump straight to the first conditional type block.
2256+ IGF.Builder .CreateBr (conditionalTypes.front ());
2257+
2258+ // For each conditionally available substitution
2259+ // (the last one is universal):
2260+ // - check all of the conditions via `isOSVersionAtLeast`
2261+ // - if all checks are true - emit a return of a result value.
2262+ for (unsigned i = 0 ; i < substitutionSet.size () - 1 ; ++i) {
2263+ auto *underlyingTy = substitutionSet[i];
2264+
2265+ IGF.Builder .emitBlock (conditionalTypes[i]);
2266+
2267+ auto returnTypeBB =
2268+ IGF.createBasicBlock (" result-" + llvm::utostr (i));
2269+
2270+ // Emit a #available condition check, if it's `false` -
2271+ // jump to the next conditionally available type.
2272+ auto conditions = underlyingTy->getAvailability ();
2273+
2274+ SmallVector<llvm::BasicBlock *, 4 > conditionBlocks;
2275+ for (unsigned condIndex : indices (conditions)) {
2276+ // cond-<type_idx>-<cond_index>
2277+ conditionBlocks.push_back (IGF.createBasicBlock (
2278+ " cond-" + llvm::utostr (i) + " -" + llvm::utostr (condIndex)));
2279+ }
2280+
2281+ // Jump to the first condition.
2282+ IGF.Builder .CreateBr (conditionBlocks.front ());
2283+
2284+ for (unsigned condIndex : indices (conditions)) {
2285+ const auto &condition = conditions[condIndex];
2286+
2287+ assert (condition.hasLowerEndpoint ());
2288+
2289+ auto version = condition.getLowerEndpoint ();
2290+ auto *major = getInt32Constant (version.getMajor ());
2291+ auto *minor = getInt32Constant (version.getMinor ());
2292+ auto *patch = getInt32Constant (version.getSubminor ());
2293+
2294+ IGF.Builder .emitBlock (conditionBlocks[condIndex]);
2295+
2296+ auto isAtLeast =
2297+ IGF.emitTargetOSVersionAtLeastCall (major, minor, patch);
2298+
2299+ auto success = IGF.Builder .CreateICmpNE (
2300+ isAtLeast, llvm::Constant::getNullValue (IGM.Int32Ty ));
2301+
2302+ auto nextCondOrRet = condIndex == conditions.size () - 1
2303+ ? returnTypeBB
2304+ : conditionBlocks[condIndex + 1 ];
2305+
2306+ IGF.Builder .CreateCondBr (success, nextCondOrRet,
2307+ conditionalTypes[i + 1 ]);
2308+ }
2309+
2310+ {
2311+ IGF.Builder .emitBlock (returnTypeBB);
2312+ IGF.Builder .CreateRet (getResultValue (
2313+ IGF, genericEnv, underlyingTy->getSubstitutions ()));
2314+ }
2315+ }
2316+
2317+ IGF.Builder .emitBlock (conditionalTypes.back ());
2318+ auto universal = substitutionSet.back ();
2319+
2320+ assert (universal->getAvailability ().size () == 1 &&
2321+ universal->getAvailability ()[0 ].isEmpty ());
2322+
2323+ IGF.Builder .CreateRet (
2324+ getResultValue (IGF, genericEnv, universal->getSubstitutions ()));
2325+ }
2326+
2327+ return getAddrOfMetadataAccessor (symbol, accessor);
2328+ }
2329+
2330+ private:
2331+ llvm::Function *getAccessorFn (std::string symbol) const {
2332+ auto fnTy = llvm::FunctionType::get (getResultType (), {IGM.Int8PtrTy },
2333+ /* vararg*/ false );
2334+
2335+ auto *accessor = llvm::Function::Create (
2336+ fnTy, llvm::GlobalValue::PrivateLinkage, symbol, IGM.getModule ());
2337+
2338+ accessor->setAttributes (IGM.constructInitialAttributes ());
2339+
2340+ return accessor;
2341+ }
2342+
2343+ llvm::Constant *
2344+ getAddrOfMetadataAccessor (std::string symbol,
2345+ llvm::Function *accessor) const {
2346+ return IGM.getAddrOfStringForMetadataRef (
2347+ symbol, /* align*/ 2 ,
2348+ /* low bit*/ false , [&](ConstantInitBuilder &B) {
2349+ // Form the mangled name with its relative reference.
2350+ auto S = B.beginStruct ();
2351+
2352+ S.setPacked (true );
2353+ S.add (llvm::ConstantInt::get (IGM.Int8Ty , 255 ));
2354+ S.add (llvm::ConstantInt::get (IGM.Int8Ty , 9 ));
2355+ S.addRelativeAddress (accessor);
2356+
2357+ // And a null terminator!
2358+ S.addInt (IGM.Int8Ty , 0 );
2359+
2360+ return S.finishAndCreateFuture ();
2361+ });
2362+ }
2363+ };
2364+
2365+ class UnderlyingTypeAccessor final : public AbstractMetadataAccessor {
2366+ // / The index of the generic parameter accessor is going
2367+ // / to retrieve the underlying type for.
2368+ unsigned OpaqueParamIndex;
2369+
2370+ public:
2371+ UnderlyingTypeAccessor (IRGenModule &IGM, OpaqueTypeDecl *O,
2372+ unsigned opaqueParamIndex)
2373+ : AbstractMetadataAccessor(IGM, O),
2374+ OpaqueParamIndex (opaqueParamIndex) {}
2375+
2376+ std::string getSymbol () const override {
2377+ IRGenMangler mangler;
2378+ return mangler.mangleSymbolNameForUnderlyingTypeAccessorString (
2379+ O, OpaqueParamIndex);
2380+ }
2381+
2382+ llvm::Type *getResultType () const override {
2383+ return IGM.TypeMetadataPtrTy ;
2384+ }
2385+
2386+ llvm::Value *
2387+ getResultValue (IRGenFunction &IGF, GenericEnvironment *genericEnv,
2388+ SubstitutionMap substitutions) const override {
2389+ auto type =
2390+ Type (O->getOpaqueGenericParams ()[OpaqueParamIndex])
2391+ .subst (substitutions)
2392+ ->getCanonicalType (O->getOpaqueInterfaceGenericSignature ());
2393+
2394+ type = genericEnv
2395+ ? genericEnv->mapTypeIntoContext (type)->getCanonicalType ()
2396+ : type;
2397+
2398+ return IGF.emitTypeMetadataRef (type);
2399+ }
2400+ };
2401+
2402+ class WitnessTableAccessor final : public AbstractMetadataAccessor {
2403+ // / The requirement itself.
2404+ const Requirement &R;
2405+
2406+ // / Protocol requirement.
2407+ ProtocolDecl *P;
2408+
2409+ public:
2410+ WitnessTableAccessor (IRGenModule &IGM, OpaqueTypeDecl *O,
2411+ const Requirement &requirement, ProtocolDecl *P)
2412+ : AbstractMetadataAccessor(IGM, O), R(requirement), P(P) {}
2413+
2414+ std::string getSymbol () const override {
2415+ IRGenMangler mangler;
2416+ return mangler.mangleSymbolNameForUnderlyingWitnessTableAccessorString (
2417+ O, R, P);
2418+ }
2419+
2420+ llvm::Type *getResultType () const override {
2421+ return IGM.WitnessTablePtrTy ;
2422+ }
2423+
2424+ llvm::Value *
2425+ getResultValue (IRGenFunction &IGF, GenericEnvironment *genericEnv,
2426+ SubstitutionMap substitutions) const override {
2427+ auto underlyingDependentType = R.getFirstType ()->getCanonicalType ();
2428+
2429+ auto underlyingType =
2430+ underlyingDependentType.subst (substitutions)->getCanonicalType ();
2431+ auto underlyingConformance =
2432+ substitutions.lookupConformance (underlyingDependentType, P);
2433+
2434+ if (underlyingType->hasTypeParameter ()) {
2435+ auto sig = genericEnv->getGenericSignature ();
2436+ underlyingConformance = underlyingConformance.subst (
2437+ underlyingType, QueryInterfaceTypeSubstitutions (genericEnv),
2438+ LookUpConformanceInSignature (sig.getPointer ()));
2439+
2440+ underlyingType = genericEnv->mapTypeIntoContext (underlyingType)
2441+ ->getCanonicalType ();
2442+ }
2443+
2444+ return emitWitnessTableRef (IGF, underlyingType, underlyingConformance);
2445+ }
2446+ };
21472447 };
21482448} // end anonymous namespace
21492449
0 commit comments