You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

34 lines
1.7 KiB

In order to buy some performance on the common, uninstrumented, fast path, we replace repeated
checks for both allocation instrumentation and allocator changes by a single function table
dispatch, and templatized allocation code that can be used to generate either instrumented
or uninstrumented versions of allocation routines.
When we call an allocation routine, we always indirect through a thread-local function table that
either points to instrumented or uninstrumented allocation routines. The instrumented code has a
`kInstrumented` = true template argument (or `kIsInstrumented` in some places), the uninstrumented
code has `kInstrumented` = false.
The function table is thread-local. There appears to be no logical necessity for that; it just
makes it easier to access from compiled Java code.
- The function table is switched out by `InstrumentQuickAllocEntryPoints[Locked]`, and a
corresponding `UninstrumentQuickAlloc`... function.
- These in turn are called by `SetStatsEnabled()`, `SetAllocationListener()`, et al, which
require the mutator lock is not held.
- With a started runtime, `SetEntrypointsInstrumented()` calls `ScopedSupendAll(`) before updating
the function table.
Mutual exclusion in the dispatch table is thus ensured by the fact that it is only updated while
all other threads are suspended, and is only accessed with the mutator lock logically held,
which inhibits suspension.
To ensure correctness, we thus must:
1. Suspend all threads when swapping out the dispatch table, and
2. Make sure that we hold the mutator lock when accessing it.
3. Not trust kInstrumented once we've given up the mutator lock, since it could have changed in the
interim.