@@ -2044,39 +2044,19 @@ namespace {
2044
2044
addGenericSignature ();
2045
2045
addUnderlyingTypeAndConformances ();
2046
2046
}
2047
-
2048
- void addUnderlyingTypeAndConformances () {
2049
- auto sig = O->getOpaqueInterfaceGenericSignature ();
2050
- auto contextSig = O->getGenericSignature ().getCanonicalSignature ();
2051
- auto subs = *O->getUniqueUnderlyingTypeSubstitutions ();
2052
2047
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));
2059
2051
}
2060
2052
2061
- // Add witness tables for each of the conformance requirements.
2053
+ auto sig = O-> getOpaqueInterfaceGenericSignature ();
2062
2054
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));
2077
2057
}
2078
2058
}
2079
-
2059
+
2080
2060
bool isUniqueDescriptor () {
2081
2061
switch (LinkEntity::forOpaqueTypeDescriptor (O)
2082
2062
.getLinkage (NotForDefinition)) {
@@ -2152,6 +2132,326 @@ namespace {
2152
2132
2153
2133
return O->getOpaqueGenericParams ().size () + numWitnessTables;
2154
2134
}
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
+ };
2155
2455
};
2156
2456
} // end anonymous namespace
2157
2457
0 commit comments