We cannot use field offset globals if *any* field of a generic class
with Objective-C ancestry is dependent.
This is because the Swift runtime first performs layout starting
from a static instance start offset, and then asks the Objective-C
runtime to slide the offsets based on the dynamic superclass size.
So if the class has a field of generic type, the alignment of that
type can change the offsets of fields *before* it as well as after.
So we cannot assuem that any fields in such a class have the same
offset across instantiations at all.
The previous fix captured the intent of the above, but it only
kicked in if the immediate superclass of the class was imported
from Objective-C. But really we need to do this for any class with
Objective-C ancestry.
While fixing this, re-organize the code in ClassLayoutBuilder a
little bit to untangle the stored property iteration from the
interesting FieldAccess adjustments that take place after.
Previously we would recursively get the abstract layout for the fully
generic class type for every superclass. But really we only need to do
that for fields of the class itself, not any superclass fields, since
we throw out the superclass field information anyway.
The type info for a class described its layout using a combination of a
StructLayout and ClassLayout, with different information stored in both.
Since we never use a class as a struct, it's simpler to add the relevant
bits to ClassLayout, and not build a StructLayout at all.
Also, drop inherited properties from the ClassLayout -- they're no
longer needed.
When emitting fixed class metadata, we emit field offsets for all fields,
including those from superclasses, if any.
Get the ClassLayout for the correct class before looking up a field that
might potentially belong to a superclass. Soon, I'm going to slim down
ClassLayout instances to only store the fields belonging to the class
itself, removing the InheritedStoredProperites array altogether.
Even if two types are different, they might still have the same
type info, so don't call getLayout() without checking the type info
for identity first. This allows simplifying an early exit into an
assertion elsewhere.
TypeBase::usesNativeReferenceCounting() was doing a lot of work to
find the class that a type refers to, then determine whether it
would use the native reference-counting scheme. Its primary caller
in IRGen would use an overly-conservative approximation to decide
between the “Objective-C” and “unknown” cases, which resulted in
uses of “unknown” reference counting for some obviously-ObjC cases
(e.g., values of “NSObject”).
Moreover, the approximation would try to call into the type checker
(because it relied unnecessarily on the superclass *type* of a class
declaration), causing an assertion.
Fixes rdar://problem/42828798.
Asking isFixedLayout() on the class's StructLayout does not take
missing members or Objective-C sliding into account. Adding a new
bit that carries this information allows removing the hack where
across modules the size of a class was always loaded from metadata.
In practice we hope most classes will be resilient, but its
better to centralize the checking for what resilience means instead
of using different rules in different places.
While most class field accesses go through accessors, a special
case is if you have a final field (or class) in a non-resilient
module. Then, we were allowed to directly access the field.
However, an earlier hack made it so that this access always went
through a field offset global, which is unnecessary in the case
where the class layout is fully known.
One consequence of this is that 'Array.count' would compile down
to a load from a global followed by an indirect load, instead of
a single load from a constant offset.
ClassDecl::getSuperclass() produces a complete interface type describing the
superclass of a class, including any generic arguments (for a generic type).
Most callers only need the referenced ClassDecl, which is (now) cheaper
to compute: switch those callers over to ClassDecl::getSuperclassDecl().
Fixes an existing test for SR-5993.
Switch a number of callers of the Type-based lookupQualified() over to
the newer (and preferred) declaration-based lookupQualified(). These are
the easy ones; NFC.
For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.
`_read` accessors do not make any effort yet to avoid copying the
value being yielded. I'll work on it in follow-up patches.
Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.
SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.
rdar://35399664
Introduce some metaprogramming of accessors and generally prepare
for storing less-structured accessor lists.
NFC except for a change to the serialization format.
Otherwise, Objective C categories don't work for classes with
resilient fields, such as the value types defined in the Foundation
overlay.
Fixes <rdar://problem/40819319>, <https://bugs.swift.org/browse/SR-7882>.
- Narrow the fix to classes with @objc ancestry only
- Pass -enable-class-resilience in class resilience executable test so that
we exercise resilience there
- Only enable fragile layout if the class has @objc ancestry
- Add an IRGen test
Type of elements contained by field offsets vector can be adjusted
to 32-bit integers (from being pointer sized) to safe space in the
binary since segment size is limited to 4 GB.
Resolves: rdar://problem/36560486
Most of the work of this patch is just propagating metadata states
throughout the system, especially local-type-data caching and
metadata-path resolution. It took a few design revisions to get both
DynamicMetadataRequest and MetadataResponse to a shape that felt
right and seemed to make everything easier.
The design is laid out pretty clearly (I hope) in the comments on
DynamicMetadataRequest and MetadataResponse, so I'm not going to
belabor it again here. Instead, I'll list out the work that's still
outstanding:
- I'm sure there are places we're asking for complete metadata where
we could be asking for something weaker.
- I need to actually test the runtime behavior to verify that it's
breaking the cycles it's supposed to, instead of just not regressing
anything else.
- I need to add something to the runtime to actually force all the
generic arguments of a generic type to be complete before reporting
completion. I think we can get away with this for now because all
existing types construct themselves completely on the first request,
but there might be a race condition there if another asks for the
type argument, gets an abstract metadata, and constructs a type with
it without ever needing it to be completed.
- Non-generic resilient types need to be switched over to an IRGen
pattern that supports initialization suspension.
- We should probably space out the MetadataStates so that there's some
space between Abstract and Complete.
- The runtime just calmly sits there, never making progress and
permanently blocking any waiting threads, if you actually form an
unresolvable metadata dependency cycle. It is possible to set up such
a thing in a way that Sema can't diagnose, and we should detect it at
runtime. I've set up some infrastructure so that it should be
straightforward to diagnose this, but I haven't actually implemented
the diagnostic yet.
- It's not clear to me that swift_checkMetadataState is really cheap
enough that it doesn't make sense to use a cache for type-fulfilled
metadata in associated type access functions. Fortunately this is not
ABI-affecting, so we can evaluate it anytime.
- Type layout really seems like a lot of code now that we sometimes
need to call swift_checkMetadataState for generic arguments. Maybe
we can have the runtime do this by marking low bits or something, so
that a TypeLayoutRef is actually either (1) a TypeLayout, (2) a known
layout-complete metadata, or (3) a metadata of unknown state. We could
do that later with a flag, but we'll need to at least future-proof by
allowing the runtime functions to return a MetadataDependency.
Rename it to swift_initClassMetadata() just like we recently did
swift_initStructMetadata(), and add a StructLayoutFlags parameter
so we can version calls to this function in the future.
Maybe at some point this will become a separate ClassLayoutFlags
type, but at this point it doesn't matter because IRGen always
passes a value of 0.
Abstract type/heap metadata access goes into MetadataRequest.
Metadata access starting from a heap object goes into GenHeap.
Accessing various components of class metadata goes into GenClass
or MetadataLayout.
The alignment of tail allocated elements was not considered in the allocation call. This caused problems for alignments > 16 bytes.
rdar://problem/37470003
This has three principal advantages:
- It gives some additional type-safety when working
with known accessors.
- It makes it significantly easier to test whether a declaration
is an accessor and encourages the use of a common idiom.
- It saves a small amount of memory in both FuncDecl and its
serialized form.
Only foreign classes and other imported types were making use of the
type metadata reference form in conformance records. Switch those over
to using nominal type descriptors, so we're using nominal type
descriptors for everything possible.
Only Objective-C-defined classes use a different representation now.
Rather than emitting unique, direct type metadata for non-foreign
types, emit a reference to the nominal type descriptor. This collapses
the set of type metadata reference kinds to 3: nominal type
descriptor, (indirect) Objective-C class object, and nonuniqued
foreign type metadata.
Adjust the IRGen for ObjC interop to ensure that the section that
metadata is emitted into the correct section for non-MachO targets.
This also adds a more comprehensive test for ensuring that the IRGen can
now be tested on all targets. Since the ObjC interop is now
controllable via the driver, this test does not require that the
objc_interop feature is present as it is a IRGen test.
This is the first step to remove the `REQUIRES: objc_interop` from the
IRGen tests.
Following up on the fixes for rdar://problem/35330067. If a class inherits a class from another module with missing fields, we need to treat its size and alignment as opaque, just like the base class itself. We also need to lay out such class at runtime, since we don't know the size, alignment, or field offsets at compile time; relying on the ObjC runtime alone will slide the ivar offsets, but not the Swift instance size and alignment. Fixes rdar://problem/35747485.
We would miscompile in mixed-language-version projects when a Swift class was compiled for one language version, while using Objective-C-imported types that are only available to that version, and then imported into a Swift module with a different language version that wasn't able to see all of the properties because of incompatible imported types. This manifested in a number of ways:
- We assumed we could re-derive the constant field offsets of the class's ivars from the layout, which is wrong if properties are missing, causing accesses to final properties or subclass properties to go to the wrong offsets.
- We assumed we could re-derive the instance size and alignment of a class instance in total, causing code to allocate the wrong amount of memory.
- We neglected to account for the space that stored properties take up in the field offset vector of the class object, causing us to load vtable entries for following subclass methods from the wrong offsets.
Eventually, resilience should reduce our exposure to these kinds of problems. As an incremental step in the right direction, when we look at a class from another module in IRGen, treat it as always variably-sized, so we don't try to hardcode offsets, size, or alignment of its instances. When we import a class, and we're unable to import a stored property, leave behind a new kind of MissingMemberDecl that records the number of field offset vector slots it will take up, so that we lay out subclass objects and compute vtable offsets correctly. Fixes rdar://problem/35330067.
A side effect of this is that the RemoteAST library is no longer able to provide fixed field offsets for class ivars. This doesn't appear to impact the lldb test suite, and they will ultimately need to use more abstract access patterns to get ivar offsets from resilient classes (if they aren't already), so I just removed the RemoteAST test cases that tested for class field offsets for now.
"Accessibility" has a different meaning for app developers, so we've
already deliberately excised it from our diagnostics in favor of terms
like "access control" and "access level". Do the same in the compiler
now that we aren't constantly pulling things into the release branch.
This commit changes the 'Accessibility' enum to be named 'AccessLevel'.