Teach swift_deallocPartialClassInstance how to deal with classes that
have pure Objective-C classes in their hierarchy. In such cases, we
need to make sure a few things happen:
1) We deallocate via objc_release rather than
swift_deallocClassInstance.
2) We only attempt to find an execute ivar destroyers for
Swift-defined classes in the hierarchy
3) When we hit the most-derived pure Objective-C class, make sure that we
only execute the dealloc of that class and not any of the subclasses
(which would end up trying to destroy ivars again).
Fixes rdar://problem/25023544.
The size of a protocol's metadata was not a multiple of 8 bytes, so
on 64-bit platforms, the runtime would copy default witnesses from
the wrong address, because IRGen metadata does not add alignment padding,
whereas the in-memory structure does.
Fix this by adding a 32-bit padding field at the end of the protocol
descriptor. Technically this is not necessary on 32-bit, but this keeps
things simpler for now.
The test case for this is a library evolution test exercising resilient
default protocol requirements, but it is not quite ready to go in yet.
Adds a rough sketch of what will be a test harness, currently only supported
on OS X:
- Launch a child process: an executable written in Swift
- Receive the child process's Mach port
- Receive reflection section addresses and the address of a heap instance
of interest
- Perform field type lookup on the instance remotely (TODO)
- Add RuntimeTarget template This will allow for converting between
metadata structures for native host and remote target architectures.
- Create InProcess and External templates for stored pointers
Add a few more types to abstract pointer access in the runtime
structures but keep native in-process pointer access the same as that
with a plain old pointer type.
There is now a notion of a "stored pointer", which is just the raw value
of the pointer, and the actual pointer type, which is used for loads.
Decoupling these allows us to fork the behavior when looking at metadata
in an external process, but keep things the same for the in-process
case.
There are two basic "runtime targets" that you can use to work with
metadata:
InProcess: Defines the pointer to be trivially a T* and stored as a
uintptr_t. A Metadata * is exactly as it was before, but defined via
AbstractMetadata<InProcess>.
External: A template that requires a target to specify its pointer size.
ExternalPointer: An opaque pointer in another address space that can't
(and shouldn't) be indirected with operator* or operator->. The memory
reader will fetch the data explicitly.
"minimal" is defined as the set of requirements that would be
passed to a function with the type's generic signature that
takes the thick metadata of the parent type as its only argument.
In principle, runtime entries could have a hidden visibility, because they are
never called directly from the code produced by IRGen.
But some of the runtime entries are invoked directly from the foundation.
Therefore they should be visible.
We annotate the most popular runtime functions in terms of how often they are invoked from Swift code:
- Many variants of retain/release functions are annotated to use the new calling convention.
But those variants of retain/release functions that may result in calls of objc_retain or objc_release
are not migrated to the new calling convention, because it results in significant performance degradations
when objects of Obj-C derived classes are used.
- Some popular non-reference counting functions like swift_getGenericMetadata or swift_dynamicCast are annotated as well.
The list of these functions is pretty much the same as the the set of functions defined in InstrumentsSupport.h
These are basically the functions that can be intercepted by different tools/profilers/etc.
This new x-macro should be used to define a runtime function that has an internal implementation
inside the runtime library and a global symbol referring to this internal implementation.
An example of such a runtime function is "swift_retain", which has a global symbol "_swift_retain"
referring to its internal implementation "_swift_retain_".
This makes sure that runtime functions use proper calling conventions, get the required visibility, etc.
We annotate the most popular runtime functions in terms of how often they are invoked from Swift code.
- Almost all variants of retain/release functions are annotated to use the new calling convention.
- Some popular non-reference counting functions like swift_getGenericMetadata or swift_dynamicCast are annotated as well.
The set of runtime functions annotated to use the new calling convention should exactly match the definitions in RuntimeFunctions.def!
Define a number of macro definitions that will be used for:
- proper auto-generation of LLVM IR level declarations of runtime function using RuntimeFunctions.def
- generation of wrappers for runtime functions
- setting proper calling conventions, visibility and other attributes of runtime functions inside the runtime library.
The generated wrapper simply invokes a corresponding entry point by means of
an indirect call via a global the symbol, which is a function pointer referring
to the implementation of a runtime function.
Using such wrappers allows for invocations of runtime functions from dynamic
libraries without the usual indirections via dynamic linker stubs.
If the calling convention and the current target require a wrapper, it will be
generated. Each wrapper gets a hidden linkage and is marked as ODR, so that
a linker can merge all wrappers with the same name.
This functionality could be re-used by e.g. LLVMPasses, which currently create LLVM IR declarations of runtime entry points on their own.
To make the function re-usable, slightly change the API of the function:
- use llvm::Module instead of IRGenModule.
- use llvm::ArrayRef instead of std::initializer_list, which allows the clients of this API to dynamically form the lists of return types and arguments.
and MetadataCache and fix a re-entrancy bug in metadata
instantiation.
The re-entrancy bug is that we were holding the instantiation
lock of a metadata cache while instantiating metadata. Doing
so prevents us from creating a different instantiation if
it's needed by the outer instantiation. This is already
possible, but it's much more likely in a patch I'm working on
to only store the minimal metadata for generic parameters
in generic types.
The same bug could also show up as a deadlock between threads,
so a recursive lock would not be a good fix. Instead, we add
a condition variable to the metadata cache. When fetching
metadata, we look for a node in the concurrent map, eagerly
creating an empty one if none currently exists. If lookup
finds an empty node, we wait on the condition variable for
the node to become populated. If lookup succeeds in creating
an empty node, we instantiate the metadata, grab the lock,
populate the node, and notify the condition variable.
Safely creating an empty node without any metadata present
requires us to move the key data into the map entry. That,
plus a few other invariant shifts, makes it sensible to
give the user of ConcurrentMap more control over the
allocation of map nodes and the layout of keys. That, in
turn, allows us to change the contract so that keys can be
more complex than just a hash code. Instead of incrementing
hash codes and re-performing the lookup, we just insist
that lookup keys be totally ordered.
For now, I've kept the uniform use of hash codes as a
component of the key for MetadataCaches. However, hash
codes aren't really profitable for small keys, and we should
probably use direct comparisons instead.
We should also switch the safer metadata caches (i.e. the
ones that don't involve calling an arbitrary instantiation
function, like MetatypeMetadataCache) over to directly use
ConcurrentMap.
LLDB's requirement that we maintain a linked list of metadata
cache instantiations with a known layout means we can't yet
remove the CacheEntry's redundant copy of the generic
arguments.