1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-27 01:01:52 -07:00

Fixed word wrap.

Copied from Perforce
 Change: 179344
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Richard Brooksby 2012-09-07 20:34:46 +01:00
parent b2f94388e4
commit 272ccfdf4a

View file

@ -192,47 +192,118 @@ System](..\manual\build.txt), part of the manual.
6. The second stage fix in the MPM
----------------------------------
If a pointer gets past the first-stage fix filters, it is passed to
`_mps_fix2`, the "second stage fix". The second stage can filter out yet more pointers using information about segments before it has to consult the pool class.
`_mps_fix2`, the "second stage fix". The second stage can filter out
yet more pointers using information about segments before it has to
consult the pool class.
The first test applied is the "tract test". The MPS looks up the tract containing the address in the tract table, which is a simple linear table indexed by the address shifted -- a kind of flat page table.
The first test applied is the "tract test". The MPS looks up the tract
containing the address in the tract table, which is a simple linear
table indexed by the address shifted -- a kind of flat page table.
Note that if the arena has been extended, the tract table becomes less simple, and this test may involved looking in more than one table. This will cause a considerable slow-down in garbage collection scanning. This is the reason that it's important to give a good estimate of the amount of address space you will ever occupy with objects when you initialize the arena.
Note that if the arena has been extended, the tract table becomes less
simple, and this test may involved looking in more than one table. This
will cause a considerable slow-down in garbage collection scanning.
This is the reason that it's important to give a good estimate of the
amount of address space you will ever occupy with objects when you
initialize the arena.
The pointer might not even be in the arena (and so not in any tract). The first stage fix doesn't guarantee it. So we eliminate any pointers not in the arena at this stage.
The pointer might not even be in the arena (and so not in any tract).
The first stage fix doesn't guarantee it. So we eliminate any pointers
not in the arena at this stage.
If the pointer is in an allocated tract, then the table also contains a cache of the "white set" -- the set of garbage collection traces for which the tract is "interesting". If a tract isn't interesting, then we know that it contains no condemned objects, and we can filter out the pointer.
If the pointer is in an allocated tract, then the table also contains a
cache of the "white set" -- the set of garbage collection traces for
which the tract is "interesting". If a tract isn't interesting, then we
know that it contains no condemned objects, and we can filter out the
pointer.
If the tract is interesting them it's part of a segment containing objects that have been condemned. The MPM can't know anything about the internal layout of the segment, so at this point we dispatch to the third stage fix.
If the tract is interesting them it's part of a segment containing
objects that have been condemned. The MPM can't know anything about the
internal layout of the segment, so at this point we dispatch to the
third stage fix.
This dispatch is slightly subtle. We have a cache of the function to dispatch to in the scan state, which has recently been looked at and is with luck still in the processor cache. The reason there is a dispatch at all is to allow for a fast changeover to emergency garbage collection, or overriding of garbage collection with extra operations. Those are beyond the scope of this document. Normally, `ss->fix` points at `PoolFix`, and we rely somewhat on modern processor [branch target prediction](https://en.wikipedia.org/wiki/Branch_target_predictor). `PoolFix` is passed the pool, which is fetched from the tract table entry, and that should be in the cache.
This dispatch is slightly subtle. We have a cache of the function to
dispatch to in the scan state, which has recently been looked at and is
with luck still in the processor cache. The reason there is a dispatch
at all is to allow for a fast changeover to emergency garbage
collection, or overriding of garbage collection with extra operations.
Those are beyond the scope of this document. Normally, `ss->fix` points
at `PoolFix`, and we rely somewhat on modern processor [branch target
prediction](https://en.wikipedia.org/wiki/Branch_target_predictor).
`PoolFix` is passed the pool, which is fetched from the tract table
entry, and that should be in the cache.
`PoolFix` itself dispatches to the pool class. Normally, a dispatch to a pool class would indirect through the pool class object. That would be a double indirection from the tract, so instead we have a cache of the pool's fix method in the pool object. This also allows a pool class to vary its fix method per pool instance, a fact that is exploited to optimize fixing in the AMC Pool depending on what kind of object format it is managing.
`PoolFix` itself dispatches to the pool class. Normally, a dispatch to
a pool class would indirect through the pool class object. That would
be a double indirection from the tract, so instead we have a cache of
the pool's fix method in the pool object. This also allows a pool class
to vary its fix method per pool instance, a fact that is exploited to
optimize fixing in the AMC Pool depending on what kind of object format
it is managing.
7. The third stage fix in the pool class
----------------------------------------
The final stage of fixing is entirely dependent on the pool class. The MPM can't, in general, know how the objects within a pool are arranged, so this is pool class specific code.
The final stage of fixing is entirely dependent on the pool class. The
MPM can't, in general, know how the objects within a pool are arranged,
so this is pool class specific code.
Furthermore, the pool class must make decisions based on the "reference rank" of the pointer. If a pointer is ambiguous (`RankAMBIG`) then it can't be changed, so even a [copying] pool class can't move an object. On the other hand, if the pointer is weak (`RankWEAK`) then the pool fix method shouldn't preserve the object at all, even if it's condemned.
Furthermore, the pool class must make decisions based on the "reference
rank" of the pointer. If a pointer is ambiguous (`RankAMBIG`) then it
can't be changed, so even a [copying] pool class can't move an object.
On the other hand, if the pointer is weak (`RankWEAK`) then the pool fix
method shouldn't preserve the object at all, even if it's condemned.
The exact details of the logic that the pool fix must implement in order to co-operate with the MPM and other pools are beyond the scope of this document, which is about the critical path. It being the critical path, it's important that whatever the pool fix does is simple and fast and returns to scanning as soon as possible.
The exact details of the logic that the pool fix must implement in order
to co-operate with the MPM and other pools are beyond the scope of this
document, which is about the critical path. It being the critical path,
it's important that whatever the pool fix does is simple and fast and
returns to scanning as soon as possible.
The first step, though, it to further filter out pointers which aren't to objects, if that's its policy. Then, it may preserve the object, according to its policy, and possibly ensure that the object gets scanned at some point in the future, if it contains more pointers.
The first step, though, it to further filter out pointers which aren't
to objects, if that's its policy. Then, it may preserve the object,
according to its policy, and possibly ensure that the object gets
scanned at some point in the future, if it contains more pointers.
As a simple example, `LOFix` is the pool fix method for the Leaf Only pool class. It implements a [marking] garbage collector, and does not have to worry about scanning preserved objects because it is used to store objects that don't contain pointers. (It is used in compiler run-time systems to store binary data such as character strings, thus avoiding any scanning, decoding, or remembered set overhead for them.)
As a simple example, `LOFix` is the pool fix method for the Leaf Only
pool class. It implements a [marking] garbage collector, and does not
have to worry about scanning preserved objects because it is used to
store objects that don't contain pointers. (It is used in compiler
run-time systems to store binary data such as character strings, thus
avoiding any scanning, decoding, or remembered set overhead for them.)
`LOFix` filters any ambiguous pointers that aren't aligned, since they can't point to objects it allocated. Otherwise it subtracts the segment base address and shifts the result to get an index into a mark bit table. If the object wasn't marked and the pointer is weak, then it sets the pointer to zero, since the object is about to be recycled. Otherwise, the mark bit is set, which preserves the object from recycling when `LOReclaim` is called later on. `LOFix` illustrates about the minimum and most efficient thing a pool fix method can do.
`LOFix` filters any ambiguous pointers that aren't aligned, since they
can't point to objects it allocated. Otherwise it subtracts the segment
base address and shifts the result to get an index into a mark bit
table. If the object wasn't marked and the pointer is weak, then it
sets the pointer to zero, since the object is about to be recycled.
Otherwise, the mark bit is set, which preserves the object from
recycling when `LOReclaim` is called later on. `LOFix` illustrates
about the minimum and most efficient thing a pool fix method can do.
8. Other considerations
-----------------------
So far this document has described the ways in which the garbage collector is designed around optimising the critical path. There are a few other things that the MPS does that are important.
So far this document has described the ways in which the garbage
collector is designed around optimising the critical path. There are a
few other things that the MPS does that are important.
Firstly, inlining is very important. The first stage fix is inlined into the format scanner by being implemented in macros in [mps.h](..\code\mps.h). And to get even better inlining, [we recommend](..\manual\build.txt) that the whole MPS is compiled in a single translation unit with the client format and that strong global optimisation is applied.
Firstly, inlining is very important. The first stage fix is inlined
into the format scanner by being implemented in macros in
[mps.h](..\code\mps.h). And to get even better inlining, [we
recommend](..\manual\build.txt) that the whole MPS is compiled in a
single translation unit with the client format and that strong global
optimisation is applied.
Secondly, we are very careful with code annotations on the critical path. Assertions, statistics, and telemetry are all disabled on the critical path in "hot" (production) builds. (In fact, it's because the critical path is critical that we can afford to leave annotations switched on elsewhere.)
Secondly, we are very careful with code annotations on the critical
path. Assertions, statistics, and telemetry are all disabled on the
critical path in "hot" (production) builds. (In fact, it's because the
critical path is critical that we can afford to leave annotations
switched on elsewhere.)
Last, but by no means least, we pay a lot of brainpower and measurement to the critical path, and are very very careful about changing it. Code review around the critical path is especially vigilant.
Last, but by no means least, we pay a lot of brainpower and measurement
to the critical path, and are very very careful about changing it. Code
review around the critical path is especially vigilant.
And we write long documents about it.