Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 31 additions & 22 deletions vm/ByteCodeTranslator/src/cn1_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,6 @@ const int currentCodenameOneCallStackOffset = threadStateData->callStackOffset;

typedef struct CN1BibopPage {
struct CN1BibopPage* _Atomic nextAll; // append-only global registry chain
struct CN1BibopPage* nextFresh[2]; // alternating per-GC fresh-page stack links
struct CN1BibopPage* nextPool; // FREE/PARTIAL pool / SWEEP stack link
int classIndex;
int slotSize;
Expand All @@ -1305,7 +1304,16 @@ typedef struct CN1BibopPage {
// page in O(1) -- without the per-slot walk -- whenever it can PROVE the page is
// homogeneous. The fields are always present (so the struct layout is identical in
// A/B builds); only the writes/reads are gated. See cn1BibopSweep for the proof.
JAVA_BOOLEAN gcAllocedSinceSweep; // any alloc into the page since last sweep/reset
JAVA_BOOLEAN gcAllocedSinceSweep; // any alloc into the page since last sweep/reset.
// Alloc paths set it, the FREE-pool reformat
// resets it, and the grace pass reads it, all
// via relaxed __atomic ops (those can overlap
// a concurrent mark). Only the sweep accesses
// it plain: it runs on the GC thread after
// mark (program-ordered vs the grace pass) on
// retired pages no mutator holds, and the
// pool handoff mutex orders it vs the next
// owner's stores
// (owner-thread single-writer; published to the
// GC via the sweep-stack release-push)
JAVA_BOOLEAN gcNeedsReclaim; // a survivor carries a finalizer or monitor ->
Expand Down Expand Up @@ -1335,19 +1343,24 @@ typedef struct CN1BibopPage {
// idempotent across parallel markers)
int gcGraceEpoch; // upper bound on survivor epochs as of the last
// full walk (GC-thread only)
_Atomic int gcFreshEpoch[2]; // queued once on each alternating epoch stack
#ifdef CN1_GRACE_AUDIT
int gcAuditSnapshot; // QA builds only: bumpIndex at mark start.
// Relaxed __atomic access everywhere -- the
// GC writes/reads it during marking while a
// mutator can reformat the page from the
// FREE pool
#endif
} CN1BibopPage;

// Per-thread current page per size class; defined in cn1_globals.m. Touched only
// by the owning thread (alloc) and by that same thread on death.
extern __thread CN1BibopPage* bibopCurrent[CN1_BIBOP_NUM_CLASSES];
extern _Atomic long bibopBytesSinceGc;
extern _Atomic long bibopGcTriggerBytes;
// Atomic mirror of currentGcMarkValue for mutator-side adaptive/fresh-page
// Atomic mirror of currentGcMarkValue for mutator-side adaptive-policy
// decisions. currentGcMarkValue itself remains owned by the GC/mark threads.
extern _Atomic int bibopGcEpoch;
extern _Atomic int bibopBypassGeneration[CN1_BIBOP_NUM_CLASSES];
extern CN1BibopPage* _Atomic bibopFreshPages[2];
#if defined(CN1_GC_INSTRUMENT) && !defined(CN1_DISABLE_BIBOP)
// QA-only diagnostics. Production builds contain neither the counters nor
// their atomic updates.
Expand All @@ -1359,7 +1372,6 @@ extern _Atomic long cn1BibopBeltRuns;
extern _Atomic long cn1BibopAdoptedRescanSkips;
#endif
extern int currentGcMarkValue;
extern void cn1BibopNoteFreshAllocation(CN1BibopPage* page, int epoch);
#ifndef CN1_BIBOP_NO_FASTSWEEP
// Called from monitorEnter (any thread) when a monitor (CN1ThreadData) is freshly
// attached to a heap object. If the object is a BiBOP slot it bumps a global live-monitor
Expand Down Expand Up @@ -1471,17 +1483,18 @@ static inline JAVA_OBJECT cn1BibopFastAlloc(CODENAME_ONE_THREAD_STATE, int size,
#endif
__atomic_store_n(&o->__codenameOneGcMark, -1, __ATOMIC_RELEASE);
atomic_store_explicit(&p->bumpIndex, bi + 1, memory_order_release);
int __cn1FreshEpoch = atomic_load_explicit(&bibopGcEpoch, memory_order_relaxed);
if(__builtin_expect(atomic_load_explicit(&p->gcFreshEpoch[__cn1FreshEpoch & 1], memory_order_relaxed)
!= __cn1FreshEpoch, 0)) {
cn1BibopNoteFreshAllocation(p, __cn1FreshEpoch);
}
#ifndef CN1_BIBOP_NO_FASTSWEEP
// Mark the page dirty so the O(1) sweep never treats a page that still has
// fresh mark==-1 (grace-candidate) slots as homogeneous. Single plain store
// to the already-hot page header; published to the GC by the eventual
// retire release-push.
p->gcAllocedSinceSweep = JAVA_TRUE;
// Mark the page dirty: the O(1) sweep never treats a page that still has
// fresh mark==-1 (grace-candidate) slots as homogeneous, and the grace
// pass slot-scans exactly the flagged pages ("-1 slot present" implies
// "allocated into since last sweep" -- the sweep converts every -1 it
// sees). Relaxed atomic (compiles to the same plain store on the hot
// path) because the GRACE PASS reads this concurrently: pre-mark stores
// are ordered ahead of it by the mark-start thread pause, and a store
// it can still miss is by definition a during-mark allocation --
// SATB-covered this cycle and rescanned next cycle since only the
// sweep (never a concurrent phase) clears the flag.
__atomic_store_n(&p->gcAllocedSinceSweep, JAVA_TRUE, __ATOMIC_RELAXED);
#endif
CN1_BIBOP_ACCOUNT_BYTES(threadStateData, p->slotSize);
// allocationsSinceLastGC / totalAllocations (the isHighFrequencyGC heuristic)
Expand Down Expand Up @@ -1559,13 +1572,9 @@ static inline JAVA_OBJECT cn1BibopFastAllocNoZero(CODENAME_ONE_THREAD_STATE, int
#endif
__atomic_store_n(&o->__codenameOneGcMark, -1, __ATOMIC_RELEASE);
atomic_store_explicit(&p->bumpIndex, bi + 1, memory_order_release);
int __cn1FreshEpoch = atomic_load_explicit(&bibopGcEpoch, memory_order_relaxed);
if(__builtin_expect(atomic_load_explicit(&p->gcFreshEpoch[__cn1FreshEpoch & 1], memory_order_relaxed)
!= __cn1FreshEpoch, 0)) {
cn1BibopNoteFreshAllocation(p, __cn1FreshEpoch);
}
#ifndef CN1_BIBOP_NO_FASTSWEEP
p->gcAllocedSinceSweep = JAVA_TRUE;
// relaxed: concurrently read by the grace pass (see cn1BibopFastAlloc)
__atomic_store_n(&p->gcAllocedSinceSweep, JAVA_TRUE, __ATOMIC_RELAXED);
#endif
CN1_BIBOP_ACCOUNT_BYTES(threadStateData, p->slotSize);
return o;
Expand Down
Loading
Loading