In the new ABI, we use the legacy type encoding in the selector and the
extended type encoding in the types field. We want to only expose the
legacy type encoding through existing APIs.
Extended type encodings add more detailed information to object and
block types:
* Objects are encoded as @"ClassName".
* Blocks are encoded as @?<parameter type signature>
In the new ABI, we use classic type encodings for selectors and extended
type encodings everywhere else.
With the old ABI, we generated a copy of every protocol in every
compilation unit that declared it. We now emit protocols only if they
are referenced (and have the linker deduplicate them).
This test was previously failing with the Apple runtime.
These are currently ignored, because they are only important when the
runtime has upgraded the protocol. The runtime will upgrade legacy
protocols, but they are not referenced by this indirection layer.
Without this fix, we would lose associated objects silently after adding
the 11th. We would also allocate full pages for each object after the
11th because we couldn't find empty slots.
* use fiber local storage if NO_PTHREADS is defined
* use critical sections instead of mutexes
Contributing-author: Ben Viglietta <benvi@microsoft.com>
It looks like this was the initial intent of 4ea82e1, but as implemented
it would still only scan the unresolved class list once. Since
unresolved_class_list represents the head and classes are pushed onto
the head, any classes added to the resolution list after resolution
started would be skipped.
This commit fixes a data loss bug in our hopscotch table implementation.
Removing values from the table can result in other values becoming
disconnected and lost.
Let A, B, and C be values that all hash to cell 0.
Assume the hopscotch distance factor H = 2.
0 1 2
+-----+-----+-----+
| | | |
+-----+-----+-----+
After adding A
0 1 2
+-----+-----+-----+
| A | | |
+-----+-----+-----+
|
+-Neighbors =
After adding B
0 1 2
+-----+-----+-----+
| A | B | |
+-----+-----+-----+
|
+-Neighbors = 1
After adding C
0 1 2
+-----+-----+-----+
| A | B | C |
+-----+-----+-----+
|
+-Neighbors = 1, 2
If we then remove B,
0 1 2
+-----+-----+-----+
| A | [X] | C |
+-----+-----+-----+
|
+-Neighbors = 1, 2
* It is replaced with a placeholder [X].
* A's neighbor table is not updated to reflect the loss.
If we then remove A,
0 1 2
+-----+-----+-----+
| [X] | [X] | [C] |
+-----+-----+-----+
|
+-Neighbors = 2
* The table is rebalanced to promote A's lowest neighbor to the primary
cell position.
* C from cell 2 remains cell 0's neighbor.
The bug manifests if [X] the placeholder value passes the null check set
out in MAP_TABLE_VALUE_NULL; that is, the placeholder is "effectively
null".
Looking up the key that matches C will first evaluate its base cell, the
one that collided with the key in the first place. Since that is
placeholder [X], and [X] is "effectively null", the lookup stops.
C is never retrieved from the hash table.
---
The expedient solution to this bug is to update cell 0's neighbors when
B is first removed, effectively skipping the hole:
If we remove B as above,
0 1 2
+-----+-----+-----+
| A | [X] | C |
+-----+-----+-----+
|
+-Neighbors = 2 <<< HERE
but clear the neighbor bit for cell 1, the promotion that happens when A
is later removed places C in cell 0.
0 1 2
+-----+-----+-----+
| C | [X] | [X] |
+-----+-----+-----+
|
+-Neighbors =
We're now using a new class and category structure and auto-upgrading the old ones. Other changes:
- The Ivar structure now points to the ivar offset variable, so we can more easily find it.
- Categories can now add properties.
This probably didn't make a difference, but if we ended up
resolving a class as a result of resolving a subclass, then we'd previously go and explore an unrelated linked list for a bit.