This code rearchitects and simplifies the projectEnumValue support by
introducing a new `TypeInfo` subclass for each kind of enum, including trivial,
no-payload, single-payload, and three different classes for multi-payload enums:
* "UnsupportedEnum" that we don't understand. This returns "don't know" answers for all requests in cases where the runtime lacks enough information to accurately handle a particular enum.
* MP Enums that only use a separate tag value. This includes generic enums and other dynamic layouts, as well as enums whose payloads have no spare bits.
* MP Enums that use spare bits, possibly in addition to a separate tag. This logic can only be used, of course, if we can in fact compute a spare bit mask that agrees with the compiler.
The final challenge is to choose one of the above three handlings for every MPE. Currently, we do not have an accurate source of information for the spare bit mask, so we never choose the third option above. We use the second option for dynamic MPE layouts (including generics) and the first for everything else.
TODO: Once we can arrange for the compiler to expose spare bit mask data, we'll be able to use that to drive more MPE cases.
* First part of multi-payload enum support
This handles multi-payload enums with fixed
layouts that don't use spare payload bits.
It includes XI calculations that allow us to
handle single-payload enums where the payload
ultimately includes a multi-payload enum
(For example, on 32-bit platforms, String uses
a multi-payload enum, so this now supports single-payload
enums carrying Strings.)
Teach RemoteMirror how to project enum values
This adds two new functions to the SwiftRemoteMirror
facility that support inspecting enum values.
Currently, these support non-payload enums and
single-payload enums, including nested enums and
payloads with struct, tuple, and reference payloads.
In particular, it handles nested `Optional` types.
TODO: Multi-payload enums use different strategies for
encoding the cases that aren't yet supported by this
code.
Note: This relies on information from dataLayoutQuery
to correctly decode invalid pointer values that are used
to encode enums. Existing clients will need to augment
their DLQ functions before using these new APIs.
Resolves rdar://59961527
```
/// Projects the value of an enum.
///
/// Takes the address and typeref for an enum and determines the
/// index of the currently-selected case within the enum.
///
/// Returns true iff the enum case could be successfully determined.
/// In particular, note that this code may fail for valid in-memory data
/// if the compiler is using a strategy we do not yet understand.
SWIFT_REMOTE_MIRROR_LINKAGE
int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef,
swift_addr_t EnumAddress,
swift_typeref_t EnumTypeRef,
uint64_t *CaseIndex);
/// Finds information about a particular enum case.
///
/// Given an enum typeref and index of a case, returns:
/// * Typeref of the associated payload or zero if there is no payload
/// * Name of the case if known.
///
/// The Name points to a freshly-allocated C string on the heap. You
/// are responsible for freeing the string (via `free()`) when you are finished.
SWIFT_REMOTE_MIRROR_LINKAGE
int swift_reflection_getEnumCaseTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t EnumTypeRef,
unsigned CaseIndex,
char **CaseName,
swift_typeref_t *PayloadTypeRef);
```
Co-authored-by: Mike Ash <mikeash@apple.com>
The swiftReflection library is only being built under a standard library
build. The check is already present at a higher level, so there is no
need to replicate the check.
To allow more pervasive use of TypeRefs in LLDB, we need a way to build mangled
names from TypeRef pointers to allow round-tripping between TypeRefs and AST
types. The goal is to experiment with making lldb::CompilerType backed by
TypeRefs instead of AST types.
<rdar://problem/55412775>
In particular, this fixes the size calculation for nested enums,
specifically enums within Optionals. Without this, the
reflection library computes `v` below as requiring two bytes
instead of one.
```
enum E {
case a
case b
}
let v = Optional<E>
```
This also adds a number of test cases for enums alone and
wrapped in optionals, including:
* Zero-case enums are allocated zero size and have zero extra inhabitants
* Zero-case enums in optionals also get zero size
* One-case no-payload enums are allocated zero size and have zero extra inhabitants
* One-case no-payload enums in optionals get one byte allocated and have zero extra inhabitants
* 254-case enums have only two extra inhabitants, so putting them in thrice-nested optionals requires an extra byte
* Various cases where each nested optional gets an extra byte
Resolves rdar://31154770
We would build two copies of swiftReflection, one for the host and one
for the target. However, the compiler configuration cannot be swapped
out in the middle as we were attempting to do. This would result in a
failure to build sometimes due to the missing dependency on the wanted
compiler. More importantly, it would also use the wrong compiler when
building the library. Although this duplicates the source paths,
correctness is preserved.
The code was skipping 4/8 bytes to jump overn embedded reference, but it actually needs to skip 5/9 bytes in order to skip over the leading control character as well.
Also change the abort() calls to return nullptr so that we can fail more gracefully if this code is ever presented with bad data, since we want inspection tools to be robust in the face of garbage.
rdar://problem/56460096
TypeRefBuilder and MetadataReader had nearly identical symbolic reference resolvers,
but diverged because TypeRefBuilder had its own local/remote address management mechanism,
and because TypeRefBuilder tries to resolve opaque types to their underlying types, whereas
other MetadataReader clients want to preserve them as written in source. The first problem
has been addressed by making TypeRefBuilder use `RemoteRef` everywhere, and the second
can be handled with a flag (and might be able to be handled more elegantly with some more
refactoring of general opaque type handling in MetadataReader).
Instead of passing around raw local pointers and references, and spreading
tricky offset arithmetic around with the Local/RemoteAddress fields in
ReflectionInfo, have the TypeRefBuilder code use RemoteRefs everywhere,
which keep the remote/local mapping together in one unit and provide
centralized API for this logic.
This doesn't yet change how code uses the RemoteRef address data to
follow pointers across objects, for things like reading type refs, but
that should be much easier to do after this lands.
These are now always zero, because memory readers handle virtual address mapping.
The `swift_reflection_info_t` structure used by the C RemoteMirror API keeps
its offset fields because it's supposed to be a stable API, but we now assert that
the values are always zero.
This makes for a cleaner and less implicit-context-heavy API, and makes it easier for symbolic
reference resolvers to do context-dependent things (like map the in-memory base address back to a
remote address in MetadataReader).
There are situations where you want to build against a libc that is out
of tree or that is not the system libc (Or for cross build scenarios).
This is a change for passing the -sdk and include paths for things like
this.
The reason why I am doing this is so that I can create an adaptor class
(templated on Runtime) for reading protocol info from ReflectionInfo without
having to make ReflectionInfo itself generic. If ReflectionInfo becomes generic
on Runtime, it will cause a cascading need to mark classes in Reflection as
generic as well.
This dramatically reduces the number of needed malloc calls.
Unfortunately I had to add the implementation of SmallVectorBase::grow_pod to the runtime, as we don't link LLVM. This is a bad hack, but better than re-inventing a new SmallVector implementation.
SR-10028
rdar://problem/48575729
When compiling for a 32 bit machine, uintptr_t from ReflectionInfo will
be the integer sized to hold a 32 bit pointer, so a 64 bit pointer might
not fit.
This commit removes the solution in
0f20c486e0 and does a runtime check that
the calculated offset will fit into the target machine uintptr_t, which
might not be true for 32 bits machines trying to read 64 bits images,
which should not be that common (and those images have to have offsets
bigger than what a 32 bits number can hold).
Seems that the change in the two variables was spilling into the other
target of the file, but returning it back to the original values seems
to avoid that issue.
This should unbreak the Android CI build. In it, the Linux static
library was changing to the host compiler, and that compiler was being
used for the Android runtime library, which would have never compile
that way (since the host compiler in CI is an old-ish Clang without the
necessary argument).
If we nest a type inside a local context inside a generic type,
we have to look through the local context(s) to find the outer
generic type when stripping off generic arguments.
We don't support nominal types inside generic local context
right now, but this can happen with type aliases.
This is essentially a long-belated follow-up to Arnold's #12606.
The key observation here is that the enum-tag-single-payload witnesses
are strictly more powerful than the XI witnesses: you can simulate
the XI witnesses by using an extra case count that's <= the XI count.
Of course the result is less efficient than the XI witnesses, but
that's less important than overall code size, and we can work on
fast-paths for that.
The extra inhabitant count is stored in a 32-bit field (always present)
following the ValueWitnessFlags, which now occupy a fixed 32 bits.
This inflates non-XI VWTs on 32-bit targets by a word, but the net effect
on XI VWTs is to shrink them by two words, which is likely to be the
more important change. Also, being able to access the XI count directly
should be a nice win.
Previously, they would forward their unused spare bits to be used by other multi-payload enums, but
did not implement anything for single-payload extra inhabitants.
This restores the ability to build the standard library and the tools in two
separate build invocations. This is required to cross-compile the standard
library on various targets without building complete toolchains.
Bitwise takability is now part of the layout of a type, because
non-bitwise takable types are never stored inline in an
existential or resilient global's buffer, even if they would
fit.
The basic rule is that weak references, unknown-refcounted
unowned references, and aggregates that contain them, are not
bitwise takable, whereas everything else is bitwise takable.
Also, since the bitwise takable for an unowned reference
depends on the reference counting style, we have to record the
superclass of a protocol, if any, to correctly determine the
reference counting style of the protocol existential.
There is a build of the reflection library for the tools which we want to build
if we are building the tools. The target library should only be built if we are
building the standard library.
Right now we expect that every class and protocol has a field
descriptor that tells us if the entity is @objc or not.
For imported types, the descriptor will not exist if we did not
directly emit a field whose concrete type contains the imported
type. For example, in lldb, we might have a generic type whose
runtime substituted type includes an imported type.
In this case, TypeLowering would fail to produce a layout because
it did not find a field descriptor for the imported type.
A better approach is to have the TypeDecoder call a different
factory method for imported types, and handle them specially in
TypeLowering, bypassing the field type metadata altogether.
Remove this special case handling for building a host library as a target
library. This is the last piece needed to support cross-compiling lldb. As a
bonus, it cleans up some of the logic in our special build system.