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