Somehow, clang was generating code that accepted nil and returned nil in swift_getObjCClassFromMetadata, but is no longer doing so. Some code relies on this to work, so switch to dyn_cast_or_null to accept nil explicitly.
rdar://74895271
Take the existing CompatibilityOverride mechanism and generalize it so it can be used in both the runtime and Concurrency libraries. The mechanism is preprocessor-heavy, so this requires some tricks. Use the SWIFT_TARGET_LIBRARY_NAME define to distinguish the libraries, and use a different .def file and mach-o section name accordingly.
We want the global/main executor functions to be a little more flexible. Instead of using the override mechanism, we expose function pointers that can be set by the compatibility library, or by any other code that wants to use a custom implementation.
rdar://73726764
Some ObjC runtime calls are weak or strong depending on the deployment target. When strong, we get warnings that the NULL checks always succeed; silence them.
Some of the adjacent code looked up functions using dlsym when they aren't provided by the SDK. Our current minimum SDK always has them, so remove the dlsym workaround.
In the uncached case, we'd scan conformances, cache them, then re-query the cache. This worked fine when the cache always grew, but now we clear the cache when loading new Swift images into the process. If that happens between the scan and the re-query, we lose the entry and return a false negative.
Instead, track what we've found in the scan in a separate local table, then query that after completing the scan.
While we're in there, fix a bug in TypeLookupError where operator= accidentally copied this->Context instead of other.Context. This caused the runtime to crash when trying to print error messages due to the false negative.
Add a no-parameter constructor to TypeLookupErrorOr<> to distinguish the case where it's being initialized with nothing from the case where it's being initialized with nullptr.
Instead of scribbling each allocation as it's parceled out, scribble the entire chunk up-front. Then, when handing out an allocation, check to make sure it still has the right scribbled data in it.
To prevent rdar://problem/68997282 from regressing, verify at runtime in
debug builds that in calls to swift_allocateGenericValueMetadata the
extraDataSize argument matches the OffsetInWords and SizeInWords
specified by the GenericMetadataPartialPattern available within the
pattern argument.
initClassFieldOffsetVector writes the instanceStart and size to the class's rodata. In some cases they already match, and this write will dirty memory unnecessarily, and prevent the compiler from emitting those rodatas into read-only memory.
rdar://problem/71119533
* [Runtime] Switch MetadataCache to ConcurrentReadableHashMap.
Use StableAddressConcurrentReadableHashMap. MetadataCacheEntry's methods for awaiting a particular state assume a stable address, where it will repeatedly examine `this` in a loop while waiting on a condition variable, so we give it a stable address to accommodate that. Some of these caches may be able to tolerate unstable addresses if this code is changed to perform the necessary table lookup each time through the loop instead. Some of them store metadata inline and we assume metadata never moves, so they'll have to stay this way.
* Have StableAddressConcurrentReadableHashMap remember the last found entry and check that before doing a more expensive lookup.
* Make a SmallMutex type that stores the mutex data out of line, and use it to get LockingConcurrentMapStorage to fit into the available space on 32-bit.
rdar://problem/70220660
Add a new entry point for getting generic metadata which adds the
canonical metadata records attached to the nominal type descriptor to
the metadata cache.
Change the implementation of the primary entry-point
swift_getGenericMetadata to stop looking through canonical
prespecialized records.
Change the implementation of swift_getCanonicalSpecializedMetadata to
use the caching token attached to the nominal type descriptor to add
canonical prespecialized metadata records to the metadata cache only
once rather than using the cache variables to limit the number of times
the attempt was made.
When swift_compareTypeContextDescriptors was added, it did not auth the
TypeContextDesriptor arguments that were passed to it. Fix that here.
There are not any uses of this function yet, so there are no signs that
need to be added.
This gives us faster lookups and a small advantage in memory usage. Most of these maps need stable addresses for their entries, so we add a level of indirection to ConcurrentReadableHashMap for these cases to accommodate that. This costs some extra memory, but it's still a net win.
A new StableAddressConcurrentReadableHashMap type handles this indirection and adds a convenience getOrInsert to take advantage of it.
ConcurrentReadableHashMap is tweaked to avoid any global constructors or destructors when using it as a global variable.
ForeignWitnessTables does not need stable addresses and it now uses ConcurrentReadableHashMap directly.
rdar://problem/70056398
Previously, the metadata accessor for which canonical prespecializations
had been formed included checks against the passed-in arguments to
determine whether the access matched a prespecialized record or not.
Now that the prespecialized records are attached to the nominal type
descriptor for the type, eliminate this hard-coded generated code and
instead let swift_getGenericMetadata do the work of looking through the
prespecializations.
Previously, noncanonical records were only allowed if one of the
arguments was from the module where the record was to be emitted.
Here, that restriction is lifted. Now getSpecializedGenericMetadata
will, on first run, register all canonical metadata with the global
cache before attempting to bless the passed-in noncanonical record,
allowing noncanonical records to be for the same arguments as a
canonical record (since in the case that a canonical record does exist,
it will be returned).
The new function swift_getCanonicalSpecializedMetadata takes a metadata
request, a prespecialized non-canonical metadata, and a cache as its
arguments. The idea of the function is either to bless the provided
prespecialized metadata as canonical if there is not currently a
canonical metadata record for the type it describes or else to return
the actual canonical metadata.
When called, the metadata cache checks for a preexisting entry for this
metadata. If none is found, the passed-in prespecialized metadata is
added to the cache. Otherwise, the metadata record found in the cache
is returned.
rdar://problem/56995359
Two protocol conformance descriptors are passed to
swift_compareProtocolConformanceDecriptors from generic metadata
accessors when there is a canonical prespecialization and one of the
generic arguments has a protocol requirement.
Previously, the descriptors were incorrectly being passed without
ptrauth processing: one from the witness table in the arguments that are
passed in to the accessor and one known statically.
Here, the descriptor in the witness table is authed using the
ProtocolConformanceDescriptor schema. Then, both descriptors are signed
using the ProtocolConformanceDescriptorsAsArguments schema. Finally, in
the runtime function, the descriptors are authed.
The new function swift_compareProtocolConformanceDescriptors calls
through to the preexisting code in MetadataCacheKey which has been
extracted out from MetadataCacheKey::compareWitnessTables into a new
public static function
MetadataCacheKey::compareProtocolConformanceDescriptors.
The new function's availability is "future" for now.
The new function `swift_compareTypeContextDescriptors` is equivalent to
a call through to swift::equalContexts. The implementation it the same
as that of swift::equalContexts with the following removals:
- Handling of context descriptors of kind other outside of
ContextDescriptorKind::Type_First...ContextDescriptorKind::Type_Last.
Because the arguments are both TypeContextDescriptors, the kinds are
known to fall within that range.
- Casting to TypeContextDescriptor. The arguments are already of that
type.
For now, the new function has "future" availability.
Previously, when NDEBUG was not defined, the allocations made for value
metadata records were filled with 0xAA bytes. Here, that behavior is
both expanded to all metadata records and enabled in release builds when
the environment variable SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE is set.
During witness table instantiation, the witness table is constructed
several sources: the pattern, the resilient witnesses, the private
data, and default implementations. The private data area is the only
one that was being zeroed out; the rest we rely on always filling in
the data from the conformance descriptor and provided info.
However, witness table instantiation uses the presence of a NULL
pointer for a particular witness in the resulting table to indicate
that no witness fulfilled that requirement, so that it can fill in the
default witnesss. Except that, without zeroing that part of the table
beforehand, we aren't guaranteed to have a NULL pointer for witness
entries that the client (protocol conformance) did not know about at
the time it was compiled.
Zero out the entire witness table so default implementations can be
filled in appropriately.
Fixes rdar://problem/64295849.
`classMetadata` is only used in the ObjC path, resulting in a
`-Wunused-variable` warning. Sink the variable into the ObjC path.
Because the conversion of the metadata does not rely on the type
metadata bits in the metadata, it is safe to delay the definition and
bit adjustment to the point where it is used unifying the two ObjC
paths.
There are a few environment variables used to enable debugging options in the
runtime, and we'll likely add more over time. These are implemented with
scattered getenv() calls at the point of use. This is inefficient, as most/all
OSes have to do a linear scan of the environment for each call. It's also not
discoverable, since the only way to find these variables is to inspect the
source.
This commit places all of these variables in a central location.
stdlib/public/runtime/EnvironmentVariables.def defines all of the debug
variables including their name, type, default value, and a help string. On OSes
which make an `environ` array available, the entire array is scanned in a single
pass the first time any debug variable is requested. By quickly rejecting
variables that do not start with `SWIFT_`, we optimize for the common case where
no debug variables are set. We also have a fallback to repeated `getenv()` calls
when a full scan is not possible.
Setting `SWIFT_HELP=YES` will print out all available debug variables along with
a brief description of what they do.
When generic metadata for a class is requested in the same module where
the class is defined, rather than a call to the generic metadata
accessor or to a variant of typeForMangledNode, a call to a new
accessor--a canonical specialized generic metadata accessor--is emitted.
The new function is defined schematically as follows:
MetadataResponse `canonical specialized metadata accessor for C<K>`(MetadataRequest request) {
(void)`canonical specialized metadata accessor for superclass(C<K>)`(::Complete)
(void)`canonical specialized metadata accessor for generic_argument_class(C<K>, 1)`(::Complete)
...
(void)`canonical specialized metadata accessor for generic_argument_class(C<K>, count)`(::Complete)
auto *metadata = objc_opt_self(`canonical specialized metadata for C<K>`);
return {metadata, MetadataState::Complete};
}
where generic_argument_class(C<K>, N) denotes the Nth generic argument
which is both (1) itself a specialized generic type and is also (2) a
class. These calls to the specialized metadata accessors for these
related types ensure that all generic class types are registered with
the Objective-C runtime.
To enable these new canonical specialized generic metadata accessors,
metadata for generic classes is prespecialized as needed. So are the
metaclasses and the corresponding rodata.
Previously, the lazy objc naming hook was registered during process
execution when the first generic class metadata was instantiated. Since
that instantiation may occur "before process launch" (i.e. if the
generic metadata is prespecialized), the lazy naming hook is now
installed at process launch.
Keep the initial metadata pool to be all zeroes. Remove the hardcoded trailer at the end. Write a trailer into it when we check the environment variable the first time we allocate.