@@ -2036,39 +2036,19 @@ namespace {
2036
2036
addGenericSignature ();
2037
2037
addUnderlyingTypeAndConformances ();
2038
2038
}
2039
-
2040
- void addUnderlyingTypeAndConformances () {
2041
- auto sig = O->getOpaqueInterfaceGenericSignature ();
2042
- auto contextSig = O->getGenericSignature ().getCanonicalSignature ();
2043
- auto subs = *O->getUniqueUnderlyingTypeSubstitutions ();
2044
2039
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));
2051
2043
}
2052
2044
2053
- // Add witness tables for each of the conformance requirements.
2045
+ auto sig = O-> getOpaqueInterfaceGenericSignature ();
2054
2046
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));
2069
2049
}
2070
2050
}
2071
-
2051
+
2072
2052
bool isUniqueDescriptor () {
2073
2053
switch (LinkEntity::forOpaqueTypeDescriptor (O)
2074
2054
.getLinkage (NotForDefinition)) {
@@ -2144,6 +2124,326 @@ namespace {
2144
2124
2145
2125
return O->getOpaqueGenericParams ().size () + numWitnessTables;
2146
2126
}
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
+ };
2147
2447
};
2148
2448
} // end anonymous namespace
2149
2449
0 commit comments