Commit Graph

16 Commits

Author SHA1 Message Date
John McCall
29d036c176 Restore the linked list of all instantiations used by LLDB, which I accidentally broke while reshuffling code. 2016-02-25 09:13:31 -08:00
practicalswift
a686c74403 [gardening] Fix recently introduced typo: "nofify" → "notify" 2016-02-25 15:13:54 +01:00
John McCall
fc261045a5 Optimize the number of accesses performed on ConcurrentMap
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.
2016-02-25 01:11:57 -08:00
Nadav Rotem
422764545c [Runtime] Improve the metadata hashing function.
The inputs to the hash function is pointers that have a predictable patten. The
hashes that we were generating and using for the metadata caches were not very
good, and as a result we generated very deep search trees. A small change that
improved the utilization of the 'length' field and another bit-rotate round
improved the quality of the hash function.

I am going to attach to the github commit two pictures. The first picture is the
binary with the old hash. The first tree is very deep and sparse. The second
picture is with the new hash function and the tree is very wide and uniform.  I
used the benchmark 'TypeFlood' in debug mode to generate huge amounts of
metadata.
2016-02-10 00:07:42 -08:00
Nadav Rotem
cdbf839f6c [Runtime Mem] Convert the metadata map from open to closed hash map.
This change cuts the number of mallocs() in the metadata caches in half.

The current metadata cache data structure uses a linked list for each entry in
the tree to handle collissions.  This means that we need at least two memory
allocations for each entry, one for the tree node and one for the linked list
node.

This commit changes the map used by the metadata caches from an open hash map
(that embeds a linked list at each entry) into an closed map that uses a
different hash value for each entry. With this change we no longer accept
collissions and it is now the responsibility of the user to prevent collissions.
The new get/trySet API makes this responsibility explicit. The new design also
goes well with the current design where hashing is done externally and the fact
that we don't save the full key, just the hash and the value to save memory.

This change reduces the number of allocated objects per entry in half. Instead
of allocating two 32-byte objects (one for the tree node and one for the linked
list) we just allocate a single entry that contains the hash and the value.

Unfortunately, values that are made of two 64-bit pointers (like protocol
conformance entries) are now too big for the 32-byte tree entry and are rounded
up to 48 bytes. In practice this is not a big deal because malloc has 48-byte pool
entries.
2016-02-08 22:57:50 -08:00
Slava Pestov
3624b1fc6b Runtime: Support for resiliently adding protocol requirements with default implementations
This is the first patch in a series that will allow new protocol
requirements to be added resiliently, with the runtime filling in
default implementations in witness tables.

First, this adds a new flag to the protocol descriptor indicating
that the protocol is resilient. In this case, there are two
additional fields, MinimumWitnessTableSizeInWords and
DefaultWitnessTableSizeInWords, followed by tail-allocated
default witnesses.

The swift_getGenericWitnessTable() entry point now fills in the
default witnesses from the protocol if the given witness table
template is smaller than the expected witness table size.

This also changes the layout of instantiated witness tables to move
the address point to the end of private data. Previously the private
data came after the requirements, but this meant that adding new
requirements would require sliding the private data at runtime and
accessing it indirectly. It is much simpler to access it from
negative offsets instead.

I updated IRGen to emit the new metadata, but currently all protocols
are flagged as not resilient, and default witnesses are not emitted;
this will come in a subsequent patch once some more plumbing is
in place.

To avoid generating GOT entries for references to protocols defined
in the current module, I had to add some hacks to the existing hack
for this. I'll hopefully clean this up in a principled manner later.
2016-02-04 17:34:55 -08:00
practicalswift
f91525a10f Consistent placement of "-*- [language] -*-===//" in header. 2016-01-04 09:46:20 +01:00
Zach Panzarino
e3a4147ac9 Update copyright date 2015-12-31 23:28:40 +00:00
practicalswift
071bf9ddb1 Fix typo: completly → completely 2015-12-14 00:11:25 +01:00
Joe Groff
9ea30d00fe Runtime: Remove custom operator new(InPlace).
C++ no longer imposes a null check requirement on placement 'new', and clang no longer emits the null check. This hack is no longer needed.
2015-11-18 12:31:24 -08:00
Joe Groff
a3b6bef4e5 Runtime: Use new(InPlace) in more places to avoid unwanted null checks. 2015-11-17 14:13:48 -08:00
Joe Groff
16c8a3b6c0 Runtime: Fix crash when first allocation for a metadata cache is page-sized or greater.
We incorrectly tested the uninitialized "next" pointer against MAP_FAILED, instead of the real result of mmap. Fixes rdar://problem/21659505.

Swift SVN r30030
2015-07-09 18:19:59 +00:00
Joe Groff
8ec59e5c11 Runtime: Implementation for generic typed boxes.
Provide new swift_{alloc,dealloc,project}Box2 entry points that allocate, project, and deallocate typed boxes using runtime-instantiated metadata. Give these a new metadata kind, so that external tools recognize the difference and can interpret the metadata appropriately.

Swift SVN r29714
2015-06-26 00:06:17 +00:00
Joe Groff
b4436bfc13 Runtime: Use a per-cache bump allocator to instantiate metadata.
This has a couple benefits:

- Since metadata allocations are already guarded by a lock, the allocator doesn't require synchronization, and can be much much simpler and a little faster than malloc.
- By bypassing malloc, we also avoid tools like 'heap' prying into our metadata cache and misrepresenting cache entries keyed on classes as live objects, fixing rdar://problem/20562886.

In my unscientific local tests, this appeared to give a small across-the-board improvement to Onone performance in the perf test suite, though not far enough from noise for me to declare that definitively. Fixing the bug is the bigger point here.

Swift SVN r27856
2015-04-28 04:14:06 +00:00
Joe Groff
00f7520888 IRGen/Runtime: Combine the separate per-convention function metadata caches into one.
We have enough flag bits on function types now to warrant stashing an extra word in the metadata key alongside the arguments and results, so add one, and pack the number of arguments, function convention, and 'throws' bit in there. This lets us merge the separate metadata caches for thick/thin/block/C functions into one, saving a bit of runtime memory, and simplifying a bunch of repetitive code in the runtime and IRGen.

This also fixes a subtle bug we had where the runtime getFunctionTypeMetadata function expected the result argument to be passed in the arguments array, but IRGen was passing it as a separate argument, which would have caused function type metadata to fail to be uniqued by result type.

Swift SVN r27651
2015-04-23 22:58:11 +00:00
Dmitri Hrybenko
350248dae5 Reorganize the directory structure under 'stdlib'
The standard library has grown significantly, and we need a new
directory structure that clearly reflects the role of the APIs, and
allows future growth.

See stdlib/{public,internal,private}/README.txt for more information.

Swift SVN r25876
2015-03-09 05:26:05 +00:00