Somehow ninja didn't rebuild everything, so I ended up pushing code
that didn't compile. I did a clean re-build and fixed a minor issue
in the logic, now the test passes.
When deriving substitutions from closure contexts, we end up with
a problem where we have an original type and a substituted type,
and the original type is not necessarily a type parameter.
We need to decompose the original and substituted types to derive
the substitutions that produced the substitution.
For example, deriveSubstitutions(Foo<T -> Int>, Foo<String -> Int>)
will give us a substitution of T := Int.
A TypeRef for C<T, U>, substituted to C<Int, Int>, should have the same
pointer identity as a C<Int, Int> created by other means. This prevents
repeating reflective layout work if we've already seen a particular
instantiation of a generic type.
We'd like to be able to compare TypeRefs with pointer equality,
but we can't link LLVMSupport, so make a lightweight TypeRefID
like FoldingSetID, that only supports the input types necessary
to unique TypeRefs.
rdar://problem/25924875
- added read / write lock support
- added non-fatal error support to allow use of mutex in fatal error reporting pathway
- isolated pthread implementation to it own header/cpp file pair
- expanded unit tests to cover new code as well as better test existing mutex
- removed a layer of complexity that added no real value
If the thread starts slowly enough it will succeed in taking the lock,
leading to a deadlock. We saw this test hanging on some of our bots
inside of pthread's lock acquire.
initialization in-place on demand. Initialize parent metadata
references correctly on struct and enum metadata.
Also includes several minor improvements related to relative
pointers that I was using before deciding to simply switch the
parent reference to an absolute reference to get better access
patterns.
Includes a fix since the earlier commit to make enum metadata
writable if they have an unfilled payload size. This didn't show
up on Darwin because "constant" is currently unenforced there in
global data containing relocations.
This patch requires an associated LLDB change which is being
submitted in parallel.
initialization in-place on demand. Initialize parent metadata
references correctly on struct and enum metadata.
Also includes several minor improvements related to relative
pointers that I was using before deciding to simply switch the
parent reference to an absolute reference to get better access
patterns.
`unittests/Basic/BlotMapVectorTest.cpp` references `llvm::outs()`, which is defined in `llvm/Support/raw_ostream.h`. I believe this currently works without the import because it is transitively included via some CMake incantations and conditionals in the googletest headers invovling `GTEST_NO_LLVM_RAW_OSTREAM`. I'm not sure.
In any case, including the header is more explicit. The file uses `llvm::outs()`, so it should include the header that defines it.
We do this by doing a traversal of our sorted lists in a similar manner as one
would when one is merging two such sets, i.e. one has two iterators and always
advances the iterator that has a value that is less than the other. If we ever
hit a situation where the two iterators equal, we must have a non-empty
intersection.
A unittest that exercises very basic functionality is provided as well.
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.