1d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
2d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Copyright (C) 2009 The Android Open Source Project
3d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
4d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Licensed under the Apache License, Version 2.0 (the "License");
5d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * you may not use this file except in compliance with the License.
6d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * You may obtain a copy of the License at
7d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
8d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *      http://www.apache.org/licenses/LICENSE-2.0
9d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
10d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Unless required by applicable law or agreed to in writing, software
11d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * distributed under the License is distributed on an "AS IS" BASIS,
12d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * See the License for the specific language governing permissions and
14d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * limitations under the License.
15d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
16d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
17d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include <errno.h>
18d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include <limits.h>
19d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include <sys/mman.h>
20d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "Dalvik.h"
22d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "alloc/Heap.h"
23d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "alloc/HeapBitmap.h"
24d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "alloc/HeapInternal.h"
25d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "alloc/HeapSource.h"
26d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#include "alloc/Verify.h"
27d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
28d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
29d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * A "mostly copying", generational, garbage collector.
30d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
31d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * TODO: we allocate our own contiguous tract of page frames to back
32d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * object allocations.  To cooperate with other heaps active in the
33d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * virtual machine we need to move the responsibility of allocating
34d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * pages someplace outside of this code.
35d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
36d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The other major data structures that maintain the state of the heap
37d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * are the block space table and the block queue.
38d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
39d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The block space table records the state of a block.  We must track
40d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * whether a block is:
41d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
42d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * - Free or allocated in some space.
43d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
44d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * - If the block holds part of a large object allocation, whether the
45d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *   block is the initial or a continued block of the allocation.
46d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
47d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * - Whether the block is pinned, that is to say whether at least one
48d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *   object in the block must remain stationary.  Only needed during a
49d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *   GC.
50d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
51d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * - Which space the object belongs to.  At present this means
52d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *   from-space or to-space.
53d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
54d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The block queue is used during garbage collection.  Unlike Cheney's
55d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * algorithm, from-space and to-space are not contiguous.  Therefore,
56d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * one cannot maintain the state of the copy with just two pointers.
57d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The block queue exists to thread lists of blocks from the various
58d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * spaces together.
59d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
60d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Additionally, we record the free space frontier of the heap, as
61d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * well as the address of the first object within a block, which is
62d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * required to copy objects following a large object (not currently
63d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * implemented).  This is stored in the heap source structure.  This
64d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * should be moved elsewhere to support in-line allocations from Java
65d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * threads.
66d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
67d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Allocation requests are satisfied by reserving storage from one or
68d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * more contiguous blocks.  Objects that are small enough to fit
69d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * inside a block are packed together within a block.  Objects that
70d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * are larger than a block are allocated from contiguous sequences of
71d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * blocks.  When half the available blocks are filled, a garbage
72d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * collection occurs.  We "flip" spaces (exchange from- and to-space),
73d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * copy live objects into to space, and perform pointer adjustment.
74d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
75d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Copying is made more complicated by the requirement that some
76d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * objects must not be moved.  This property is known as "pinning".
77d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * These objects must be dealt with specially.  We use Bartlett's
78d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * scheme; blocks containing such objects are grayed (promoted) at the
79952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * start of a garbage collection.  By virtue of this trick, tracing
80d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * from the roots proceeds as usual but all objects on those pages are
81d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * considered promoted and therefore not moved.
82d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
83d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * TODO: there is sufficient information within the garbage collector
84d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * to implement Attardi's scheme for evacuating unpinned objects from
85d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * a page that is otherwise pinned.  This would eliminate false
86d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * retention caused by the large pinning granularity.
87d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
88d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * We need a scheme for medium and large objects.  Ignore that for
89d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * now, we can return to this later.
90d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
91d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Eventually we need to worry about promoting objects out of the
92d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * copy-collected heap (tenuring) into a less volatile space.  Copying
93d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * may not always be the best policy for such spaces.  We should
94d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * consider a variant of mark, sweep, compact.
95d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
96d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The block scheme allows us to use VM page faults to maintain a
97d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * write barrier.  Consider having a special leaf state for a page.
98d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
99d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Bibliography:
100d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
101d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * C. J. Cheney. 1970. A non-recursive list compacting
102d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * algorithm. CACM. 13-11 pp677--678.
103d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
104d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Joel F. Bartlett. 1988. Compacting Garbage Collection with
105d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Ambiguous Roots. Digital Equipment Corporation.
106d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
107d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Joel F. Bartlett. 1989. Mostly-Copying Garbage Collection Picks Up
108d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Generations and C++. Digital Equipment Corporation.
109d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
110d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * G. May Yip. 1991. Incremental, Generational Mostly-Copying Garbage
111d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Collection in Uncooperative Environments. Digital Equipment
112d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Corporation.
113d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
114d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Giuseppe Attardi, Tito Flagella. 1994. A Customisable Memory
115d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Management Framework. TR-94-010
116d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
117d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Giuseppe Attardi, Tito Flagella, Pietro Iglio. 1998. A customisable
118d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * memory management framework for C++. Software -- Practice and
119d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Experience. 28(11), 1143-1183.
120d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro *
121d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
122d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
123d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
124d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1258bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#if 0
1264308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_ALLOC ALOGI
1274308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_PIN ALOGI
1284308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_PROM ALOGI
1294308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_REF ALOGI
1304308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_SCAV ALOGI
1314308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_TRAN ALOGI
1324308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block#define LOG_VER ALOGI
133d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#else
1348bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_ALLOC(...) ((void)0)
1358bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_PIN(...) ((void)0)
1368bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_PROM(...) ((void)0)
1378bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_REF(...) ((void)0)
1388bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_SCAV(...) ((void)0)
1398bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_TRAN(...) ((void)0)
1408bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro#define LOG_VER(...) ((void)0)
141d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
142d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
143d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void enqueueBlock(HeapSource *heapSource, size_t block);
1442396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic void scavengeReference(Object **obj);
145952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool toSpaceContains(const void *addr);
146952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool fromSpaceContains(const void *addr);
147d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic size_t sumHeapBitmap(const HeapBitmap *bitmap);
1482396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic size_t objectSize(const Object *obj);
149952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic void scavengeDataObject(Object *obj);
1501e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void scavengeBlockQueue();
151d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
152d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
153d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * We use 512-byte blocks.
154d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
155d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiroenum { BLOCK_SHIFT = 9 };
156d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiroenum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
157d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
158d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
159d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Space identifiers, stored into the blockSpace array.
160d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
161d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiroenum {
162d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    BLOCK_FREE = 0,
163d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    BLOCK_FROM_SPACE = 1,
164d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    BLOCK_TO_SPACE = 2,
165d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    BLOCK_CONTINUED = 7
166d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro};
167d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
168d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
169d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Alignment for all allocations, in bytes.
170d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
171d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiroenum { ALLOC_ALIGNMENT = 8 };
172d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
173d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
174d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Sentinel value for the queue end.
175d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
176d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#define QUEUE_TAIL (~(size_t)0)
177d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
178d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostruct HeapSource {
179d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
180d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* The base address of backing store. */
181d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *blockBase;
182d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
183d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Total number of blocks available for allocation. */
184d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t totalBlocks;
185d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t allocBlocks;
186d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
187d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
188d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * The scavenger work queue.  Implemented as an array of index
189d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * values into the queue.
190d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
191d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t *blockQueue;
192d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
193d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
194d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Base and limit blocks.  Basically the shifted start address of
195d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * the block.  We convert blocks to a relative number when
196d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * indexing in the block queue.  TODO: make the block queue base
197d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * relative rather than the index into the block queue.
198d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
199d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t baseBlock, limitBlock;
200d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
201d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t queueHead;
202d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t queueTail;
203d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t queueSize;
204d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
205d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* The space of the current block 0 (free), 1 or 2. */
206d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    char *blockSpace;
207d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
208d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Start of free space in the current block. */
209d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *allocPtr;
210d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Exclusive limit of free space in the current block. */
211d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *allocLimit;
212d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
213d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapBitmap allocBits;
214d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
215d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
216d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * The starting size of the heap.  This value is the same as the
217d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * value provided to the -Xms flag.
218d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
219d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t minimumSize;
220d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
221d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
222d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * The maximum size of the heap.  This value is the same as the
223d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * -Xmx flag.
224d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
225d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t maximumSize;
226d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
227d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
228d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * The current, committed size of the heap.  At present, this is
229d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * equivalent to the maximumSize.
230d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
231d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t currentSize;
232d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
233d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t bytesAllocated;
234d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro};
235d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
236d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic unsigned long alignDown(unsigned long x, unsigned long n)
237d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
238d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return x & -n;
239d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
240d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
241d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic unsigned long alignUp(unsigned long x, unsigned long n)
242d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
243d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return alignDown(x + (n - 1), n);
244d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
245d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
246d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void describeBlocks(const HeapSource *heapSource)
247d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
248f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
249d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if ((i % 32) == 0) putchar('\n');
250d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        printf("%d ", heapSource->blockSpace[i]);
251d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
252d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    putchar('\n');
253d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
254d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
255d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
256d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Virtual memory interface.
257d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
258d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
259d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void *virtualAlloc(size_t length)
260d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
261f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
262f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    int prot = PROT_READ | PROT_WRITE;
263f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    void *addr = mmap(NULL, length, prot, flags, -1, 0);
264d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (addr == MAP_FAILED) {
265d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        LOGE_HEAP("mmap: %s", strerror(errno));
266d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        addr = NULL;
267d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
268d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return addr;
269d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
270d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
271d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void virtualFree(void *addr, size_t length)
272d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
273d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(addr != NULL);
274d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert((uintptr_t)addr % SYSTEM_PAGE_SIZE == 0);
275f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    int res = munmap(addr, length);
276d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (res == -1) {
277d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        LOGE_HEAP("munmap: %s", strerror(errno));
278d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
279d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
280d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
281eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro#ifndef NDEBUG
282d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic int isValidAddress(const HeapSource *heapSource, const u1 *addr)
283d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
284d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t block;
285d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
286d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    block = (uintptr_t)addr >> BLOCK_SHIFT;
287d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return heapSource->baseBlock <= block &&
288d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro           heapSource->limitBlock > block;
289d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
290eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro#endif
291d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
292d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
293d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Iterate over the block map looking for a contiguous run of free
294d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * blocks.
295d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
296d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void *allocateBlocks(HeapSource *heapSource, size_t blocks)
297d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
298f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t allocBlocks = heapSource->allocBlocks;
299f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t totalBlocks = heapSource->totalBlocks;
300d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Check underflow. */
301d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(blocks != 0);
302d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Check overflow. */
303d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (allocBlocks + blocks > totalBlocks / 2) {
304d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return NULL;
305d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
306d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scan block map. */
307f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < totalBlocks; ++i) {
308d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* Check fit. */
309f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        for (size_t j = 0; j < blocks; ++j) { /* runs over totalBlocks */
310d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            if (heapSource->blockSpace[i+j] != BLOCK_FREE) {
311d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                break;
312d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
313d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
314d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* No fit? */
315d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (j != blocks) {
316d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            i += j;
317d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
318d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
319d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* Fit, allocate. */
320d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->blockSpace[i] = BLOCK_TO_SPACE; /* why to-space? */
321f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        for (size_t j = 1; j < blocks; ++j) {
322d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->blockSpace[i+j] = BLOCK_CONTINUED;
323d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
324d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->allocBlocks += blocks;
325f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        void *addr = &heapSource->blockBase[i*BLOCK_SIZE];
326d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        memset(addr, 0, blocks*BLOCK_SIZE);
327d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* Collecting? */
328d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (heapSource->queueHead != QUEUE_TAIL) {
329d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            LOG_ALLOC("allocateBlocks allocBlocks=%zu,block#=%zu", heapSource->allocBlocks, i);
330d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /*
331d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * This allocated was on behalf of the transporter when it
332d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * shaded a white object gray.  We enqueue the block so
333d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * the scavenger can further shade the gray objects black.
334d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             */
335d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            enqueueBlock(heapSource, i);
336d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
337d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
338d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return addr;
339d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
340d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Insufficient space, fail. */
341c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block    ALOGE("Insufficient space, %zu blocks, %zu blocks allocated and %zu bytes allocated",
342d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         heapSource->totalBlocks,
343d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         heapSource->allocBlocks,
344d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         heapSource->bytesAllocated);
345d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return NULL;
346d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
347d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
348d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/* Converts an absolute address to a relative block number. */
349d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic size_t addressToBlock(const HeapSource *heapSource, const void *addr)
350d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
351d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
352d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(isValidAddress(heapSource, addr));
353d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return (((uintptr_t)addr) >> BLOCK_SHIFT) - heapSource->baseBlock;
354d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
355d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
356d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/* Converts a relative block number to an absolute address. */
357d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic u1 *blockToAddress(const HeapSource *heapSource, size_t block)
358d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
359d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *addr;
360d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
361d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    addr = (u1 *) (((uintptr_t) heapSource->baseBlock + block) * BLOCK_SIZE);
362d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(isValidAddress(heapSource, addr));
363d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return addr;
364d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
365d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
366d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void clearBlock(HeapSource *heapSource, size_t block)
367d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
368d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
369d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(block < heapSource->totalBlocks);
370f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    u1 *addr = heapSource->blockBase + block*BLOCK_SIZE;
371d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    memset(addr, 0xCC, BLOCK_SIZE);
372f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < BLOCK_SIZE; i += 8) {
373d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        dvmHeapBitmapClearObjectBit(&heapSource->allocBits, addr + i);
374d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
375d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
376d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
377d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void clearFromSpace(HeapSource *heapSource)
378d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
379d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
380f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t i = 0;
381f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t count = 0;
382d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (i < heapSource->totalBlocks) {
383d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (heapSource->blockSpace[i] != BLOCK_FROM_SPACE) {
384d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            ++i;
385d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
386d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
387d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->blockSpace[i] = BLOCK_FREE;
388d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        clearBlock(heapSource, i);
389d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        ++i;
390d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        ++count;
391d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        while (i < heapSource->totalBlocks &&
392d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro               heapSource->blockSpace[i] == BLOCK_CONTINUED) {
393d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->blockSpace[i] = BLOCK_FREE;
394d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            clearBlock(heapSource, i);
395d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            ++i;
396d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            ++count;
397d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
398d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
3998bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("freed %zu blocks (%zu bytes)", count, count*BLOCK_SIZE);
400d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
401d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
402d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
403d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Appends the given block to the block queue.  The block queue is
404d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * processed in-order by the scavenger.
405d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
406d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void enqueueBlock(HeapSource *heapSource, size_t block)
407d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
408d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
409d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(block < heapSource->totalBlocks);
410d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (heapSource->queueHead != QUEUE_TAIL) {
411d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->blockQueue[heapSource->queueTail] = block;
412d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
413d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->queueHead = block;
414d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
415d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->blockQueue[block] = QUEUE_TAIL;
416d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->queueTail = block;
417d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    ++heapSource->queueSize;
418d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
419d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
420d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
421d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Grays all objects within the block corresponding to the given
422d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * address.
423d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
424d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void promoteBlockByAddr(HeapSource *heapSource, const void *addr)
425d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
426d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t block;
427d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
428d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    block = addressToBlock(heapSource, (const u1 *)addr);
429d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (heapSource->blockSpace[block] != BLOCK_TO_SPACE) {
4308bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        // LOG_PROM("promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
431d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->blockSpace[block] = BLOCK_TO_SPACE;
432d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        enqueueBlock(heapSource, block);
433d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* TODO(cshapiro): count continued blocks?*/
434d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->allocBlocks += 1;
435d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
4368bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        // LOG_PROM("NOT promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
437d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
438d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
439d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
440d28668cf8740d1f913b4e9140a8c685013c1ad18Carl ShapiroGcHeap *dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
441d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
442d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    GcHeap* gcHeap;
443d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
444d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
445d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(startSize <= absoluteMaxSize);
446d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
447b74e7190e86d559712747e5cdb31a0d390b7af7dIliyan Malchev    heapSource = calloc(1, sizeof(*heapSource));
448d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
449d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
450d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->minimumSize = alignUp(startSize, BLOCK_SIZE);
451d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->maximumSize = alignUp(absoluteMaxSize, BLOCK_SIZE);
452d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
453d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->currentSize = heapSource->maximumSize;
454d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
455d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Allocate underlying storage for blocks. */
456d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->blockBase = virtualAlloc(heapSource->maximumSize);
457d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->blockBase != NULL);
458d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->baseBlock = (uintptr_t) heapSource->blockBase >> BLOCK_SHIFT;
459d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->limitBlock = ((uintptr_t) heapSource->blockBase + heapSource->maximumSize) >> BLOCK_SHIFT;
460d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
461d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocBlocks = 0;
462d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->totalBlocks = (heapSource->limitBlock - heapSource->baseBlock);
463d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
464d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->totalBlocks = heapSource->maximumSize / BLOCK_SIZE);
465d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
466d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    {
467d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size_t size = sizeof(heapSource->blockQueue[0]);
468d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->blockQueue = malloc(heapSource->totalBlocks*size);
469d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(heapSource->blockQueue != NULL);
470d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        memset(heapSource->blockQueue, 0xCC, heapSource->totalBlocks*size);
471d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->queueHead = QUEUE_TAIL;
472d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
473d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
474d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Byte indicating space residence or free status of block. */
475d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    {
476d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size_t size = sizeof(heapSource->blockSpace[0]);
477b74e7190e86d559712747e5cdb31a0d390b7af7dIliyan Malchev        heapSource->blockSpace = calloc(1, heapSource->totalBlocks*size);
478d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(heapSource->blockSpace != NULL);
479d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
480d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
481d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHeapBitmapInit(&heapSource->allocBits,
482d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                      heapSource->blockBase,
483d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                      heapSource->maximumSize,
484d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                      "blockBase");
485d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
486d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Initialize allocation pointers. */
487d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocPtr = allocateBlocks(heapSource, 1);
488d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocLimit = heapSource->allocPtr + BLOCK_SIZE;
489d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
490b74e7190e86d559712747e5cdb31a0d390b7af7dIliyan Malchev    gcHeap = calloc(1, sizeof(*gcHeap));
491d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(gcHeap != NULL);
492d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    gcHeap->heapSource = heapSource;
493d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
494d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return gcHeap;
495d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
496d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
497d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
498d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Perform any required heap initializations after forking from the
499d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * zygote process.  This is a no-op for the time being.  Eventually
500d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * this will demarcate the shared region of the heap.
501d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
5021e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmHeapSourceStartupAfterZygote()
503d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
504d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return true;
505d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
506d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
5071e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmHeapSourceStartupBeforeFork()
508d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
509d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
510d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return false;
511d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
512d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
513d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmHeapSourceShutdown(GcHeap **gcHeap)
514d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
515d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (*gcHeap == NULL || (*gcHeap)->heapSource == NULL)
516d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return;
51788b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro    free((*gcHeap)->heapSource->blockQueue);
51888b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro    free((*gcHeap)->heapSource->blockSpace);
519d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    virtualFree((*gcHeap)->heapSource->blockBase,
520d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                (*gcHeap)->heapSource->maximumSize);
521d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    free((*gcHeap)->heapSource);
522d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    (*gcHeap)->heapSource = NULL;
523d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    free(*gcHeap);
524d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    *gcHeap = NULL;
525d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
526d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
527d862faa2ceae186da5518607505eb942d634ced9Carl Shapirosize_t dvmHeapSourceGetValue(HeapSourceValueSpec spec,
528d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                             size_t perHeapStats[],
529d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                             size_t arrayLen)
530d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
531d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
532d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t value;
533d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
534d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
535d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    switch (spec) {
536d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    case HS_FOOTPRINT:
537d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        value = heapSource->maximumSize;
538d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        break;
539d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    case HS_ALLOWED_FOOTPRINT:
540d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        value = heapSource->maximumSize;
541d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        break;
542d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    case HS_BYTES_ALLOCATED:
543d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        value = heapSource->bytesAllocated;
544d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        break;
545d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    case HS_OBJECTS_ALLOCATED:
546d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        value = sumHeapBitmap(&heapSource->allocBits);
547d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        break;
548d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    default:
549d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(!"implemented");
550d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        value = 0;
551d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
552d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (perHeapStats) {
553d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        *perHeapStats = value;
554d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
555d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return value;
556d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
557d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
558d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
559d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Performs a shallow copy of the allocation bitmap into the given
560d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * vector of heap bitmaps.
561d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
562d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmHeapSourceGetObjectBitmaps(HeapBitmap objBits[], HeapBitmap markBits[],
563d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                                   size_t numHeaps)
564d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
565d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
566d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
567d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
5681e1433e78f560a01744e870c19c162ab88df9dc1Carl ShapiroHeapBitmap *dvmHeapSourceGetLiveBits()
569d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
570603469a4258a1daf35841449e29f34639115f35eCarl Shapiro    return &gDvm.gcHeap->heapSource->allocBits;
571d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
572d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
573d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
574d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Allocate the specified number of bytes from the heap.  The
575d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * allocation cursor points into a block of free storage.  If the
576d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * given allocation fits in the remaining space of the block, we
577d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * advance the cursor and return a pointer to the free storage.  If
578d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the allocation cannot fit in the current block but is smaller than
579d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * a block we request a new block and allocate from it instead.  If
580d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the allocation is larger than a block we must allocate from a span
581d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * of contiguous blocks.
582d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
583d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid *dvmHeapSourceAlloc(size_t length)
584d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
585d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
586d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    unsigned char *addr;
587d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t aligned, available, blocks;
588d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
589d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
590d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
591d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->allocPtr != NULL);
592d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->allocLimit != NULL);
593d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
594d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    aligned = alignUp(length, ALLOC_ALIGNMENT);
595d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    available = heapSource->allocLimit - heapSource->allocPtr;
596d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
597d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Try allocating inside the current block. */
598d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (aligned <= available) {
599d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        addr = heapSource->allocPtr;
600d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->allocPtr += aligned;
601d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->bytesAllocated += aligned;
602d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
603d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return addr;
604d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
605d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
606d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Try allocating in a new block. */
607d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (aligned <= BLOCK_SIZE) {
608d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        addr =  allocateBlocks(heapSource, 1);
609d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (addr != NULL) {
610d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->allocLimit = addr + BLOCK_SIZE;
611d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->allocPtr = addr + aligned;
612d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->bytesAllocated += aligned;
613d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
614d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* TODO(cshapiro): pad out the current block. */
615d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
616d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return addr;
617d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
618d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
619d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Try allocating in a span of blocks. */
620d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    blocks = alignUp(aligned, BLOCK_SIZE) / BLOCK_SIZE;
621d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
622d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    addr = allocateBlocks(heapSource, blocks);
623d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Propagate failure upward. */
624d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (addr != NULL) {
625d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->bytesAllocated += aligned;
626d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
627d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* TODO(cshapiro): pad out free space in the last block. */
628d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
629d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return addr;
630d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
631d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
632d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid *dvmHeapSourceAllocAndGrow(size_t size)
633d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
634d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return dvmHeapSourceAlloc(size);
635d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
636d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
637d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/* TODO: refactor along with dvmHeapSourceAlloc */
638d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid *allocateGray(size_t size)
639d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
6407800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    HeapSource *heapSource;
6417800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    void *addr;
6427800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    size_t block;
6437800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro
644952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* TODO: add a check that we are in a GC. */
6457800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
6467800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    addr = dvmHeapSourceAlloc(size);
647703a2f3f1acc3ecc23d37970af2638463587a40fCarl Shapiro    assert(addr != NULL);
6487800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    block = addressToBlock(heapSource, (const u1 *)addr);
6497800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    if (heapSource->queueHead == QUEUE_TAIL) {
6507800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        /*
6517800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro         * Forcibly append the underlying block to the queue.  This
6527800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro         * condition occurs when referents are transported following
6537800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro         * the initial trace.
6547800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro         */
6557800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        enqueueBlock(heapSource, block);
6567800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        LOG_PROM("forced promoting block %zu %d @ %p", block, heapSource->blockSpace[block], addr);
6577800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    }
6587800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    return addr;
659d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
660d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
661eff0df741d2b1537cf1010328000c1369559b628Carl Shapirobool dvmHeapSourceContainsAddress(const void *ptr)
662eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro{
663eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro    HeapSource *heapSource = gDvm.gcHeap->heapSource;
664eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro    return dvmHeapBitmapCoversAddress(&heapSource->allocBits, ptr);
665eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro}
666eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro
667d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
668d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Returns true if the given address is within the heap and points to
669d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the header of a live object.
670d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
671d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirobool dvmHeapSourceContains(const void *addr)
672d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
673d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
674d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapBitmap *bitmap;
675d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
676d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
677d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    bitmap = &heapSource->allocBits;
678dc1e4f1499994dca0b6796c32acaa66e436a02daCarl Shapiro    if (!dvmHeapBitmapCoversAddress(bitmap, addr)) {
679dc1e4f1499994dca0b6796c32acaa66e436a02daCarl Shapiro        return false;
680dc1e4f1499994dca0b6796c32acaa66e436a02daCarl Shapiro    } else {
681dc1e4f1499994dca0b6796c32acaa66e436a02daCarl Shapiro        return dvmHeapBitmapIsObjectBitSet(bitmap, addr);
682dc1e4f1499994dca0b6796c32acaa66e436a02daCarl Shapiro    }
683d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
684d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
6855cdd4a3f91d3fc25c8eeca8f58e35bb6c4e908caCarl Shapirobool dvmHeapSourceGetPtrFlag(const void *ptr, HeapSourcePtrFlag flag)
686d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
687d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
688d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return false;
689d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
690d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
691d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirosize_t dvmHeapSourceChunkSize(const void *ptr)
692d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
693d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
694d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return 0;
695d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
696d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
6971e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirosize_t dvmHeapSourceFootprint()
698d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
699d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
700d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return 0;
701d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
702d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
703d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
704d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Returns the "ideal footprint" which appears to be the number of
705d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * bytes currently committed to the heap.  This starts out at the
706d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * start size of the heap and grows toward the maximum size.
707d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
7081e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirosize_t dvmHeapSourceGetIdealFootprint()
709d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
710d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return gDvm.gcHeap->heapSource->currentSize;
711d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
712d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
7131e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirofloat dvmGetTargetHeapUtilization()
714d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
715603469a4258a1daf35841449e29f34639115f35eCarl Shapiro    return 0.5f;
716d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
717d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
718d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmSetTargetHeapUtilization(float newTarget)
719d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
720603469a4258a1daf35841449e29f34639115f35eCarl Shapiro    assert(newTarget > 0.0f && newTarget < 1.0f);
721d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
722d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
723d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
724d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Expands the size of the heap after a collection.  At present we
725d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * commit the pages for maximum size of the heap so this routine is
726d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * just a no-op.  Eventually, we will either allocate or commit pages
727d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * on an as-need basis.
728d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
7291e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapSourceGrowForUtilization()
730d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
731d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
732d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
733d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
734808a7c0e7e39b7ca3c7db1366e6e4089166052bbIan Rogersvoid dvmHeapSourceWalk(void(*callback)(void* start, void* end,
735808a7c0e7e39b7ca3c7db1366e6e4089166052bbIan Rogers                                       size_t used_bytes, void* arg),
736d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                       void *arg)
737d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
738d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
739d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
740d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
7411e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirosize_t dvmHeapSourceGetNumHeaps()
742d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
743d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return 1;
744d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
745d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
746d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirobool dvmTrackExternalAllocation(size_t n)
747d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
748528f381bbecd4ee90018f5e0cb2a28388790f82fCarl Shapiro    /* do nothing */
749528f381bbecd4ee90018f5e0cb2a28388790f82fCarl Shapiro    return true;
750d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
751d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
752d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmTrackExternalFree(size_t n)
753d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
754528f381bbecd4ee90018f5e0cb2a28388790f82fCarl Shapiro    /* do nothing */
755d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
756d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
7571e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirosize_t dvmGetExternalBytesAllocated()
758d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
759d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!"implemented");
760d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return 0;
761d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
762d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
7631e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapSourceFlip()
764d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
765f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HeapSource *heapSource = gDvm.gcHeap->heapSource;
766d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
767d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Reset the block queue. */
768d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocBlocks = 0;
769d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->queueSize = 0;
770d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->queueHead = QUEUE_TAIL;
771d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
772d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* TODO(cshapiro): pad the current (prev) block. */
773d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
774d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocPtr = NULL;
775d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource->allocLimit = NULL;
776d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
777d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Whiten all allocated blocks. */
778f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
779d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (heapSource->blockSpace[i] == BLOCK_TO_SPACE) {
780d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            heapSource->blockSpace[i] = BLOCK_FROM_SPACE;
781d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
782d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
783d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
784d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
785d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void room(size_t *alloc, size_t *avail, size_t *total)
786d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
787f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HeapSource *heapSource = gDvm.gcHeap->heapSource;
788d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    *total = heapSource->totalBlocks*BLOCK_SIZE;
789d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    *alloc = heapSource->allocBlocks*BLOCK_SIZE;
790d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    *avail = *total - *alloc;
791d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
792d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
793d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic bool isSpaceInternal(u1 *addr, int space)
794d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
795d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
796d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *base, *limit;
797d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t offset;
798d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    char space2;
799d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
800d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
801d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    base = heapSource->blockBase;
802d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(addr >= base);
803d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    limit = heapSource->blockBase + heapSource->maximumSize;
804d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(addr < limit);
805d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    offset = addr - base;
806d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    space2 = heapSource->blockSpace[offset >> BLOCK_SHIFT];
807d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return space == space2;
808d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
809d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
810952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool fromSpaceContains(const void *addr)
811d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
812d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return isSpaceInternal((u1 *)addr, BLOCK_FROM_SPACE);
813d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
814d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
815952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool toSpaceContains(const void *addr)
816d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
817d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return isSpaceInternal((u1 *)addr, BLOCK_TO_SPACE);
818d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
819d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
820d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
821d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Notifies the collector that the object at the given address must
822d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * remain stationary during the current collection.
823d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
824d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void pinObject(const Object *obj)
825d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
826d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    promoteBlockByAddr(gDvm.gcHeap->heapSource, obj);
827d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
828d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
829d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic size_t sumHeapBitmap(const HeapBitmap *bitmap)
830d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
831f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t sum = 0;
832f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < bitmap->bitsLen >> 2; ++i) {
833603469a4258a1daf35841449e29f34639115f35eCarl Shapiro        sum += CLZ(bitmap->bits[i]);
834d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
835d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return sum;
836d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
837d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
838d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
839d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Miscellaneous functionality.
840d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
841d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
842d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic int isForward(const void *addr)
843d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
844d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return (uintptr_t)addr & 0x1;
845d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
846d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
847d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void setForward(const void *toObj, void *fromObj)
848d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
849d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    *(unsigned long *)fromObj = (uintptr_t)toObj | 0x1;
850d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
851d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
852d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void* getForward(const void *fromObj)
853d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
854d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return (void *)((uintptr_t)fromObj & ~0x1);
855d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
856d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
857d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/* Beware, uses the same encoding as a forwarding pointers! */
858d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic int isPermanentString(const StringObject *obj) {
859d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return (uintptr_t)obj & 0x1;
860d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
861d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
862d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void* getPermanentString(const StringObject *obj)
863d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
864d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return (void *)((uintptr_t)obj & ~0x1);
865d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
866d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
867d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
868d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
869d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Scavenging and transporting routines follow.  A transporter grays
870d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * an object.  A scavenger blackens an object.  We define these
871d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * routines for each fundamental object type.  Dispatch is performed
872d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * in scavengeObject.
873d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
874d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
875d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
8762396fda0f5907178632a14d70a94257023e33d42Carl Shapiro * Class object scavenging.
877d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
8782396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic void scavengeClassObject(ClassObject *obj)
879d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
8808bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeClassObject(obj=%p)", obj);
8812396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(obj != NULL);
882d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj->obj.clazz != NULL);
883d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj->obj.clazz->descriptor != NULL);
884d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;"));
885d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj->descriptor != NULL);
8868bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeClassObject: descriptor='%s',vtableCount=%zu",
8878bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro             obj->descriptor, obj->vtableCount);
888703a2f3f1acc3ecc23d37970af2638463587a40fCarl Shapiro    /* Delegate class object and instance field scavenging. */
889703a2f3f1acc3ecc23d37970af2638463587a40fCarl Shapiro    scavengeDataObject((Object *)obj);
890d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the array element class object. */
891d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
892d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        scavengeReference((Object **)(void *)&obj->elementClass);
893d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
894d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the superclass. */
895d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference((Object **)(void *)&obj->super);
896d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the class loader. */
897d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&obj->classLoader);
898d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge static fields. */
899f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (int i = 0; i < obj->sfieldCount; ++i) {
900d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        char ch = obj->sfields[i].field.signature[0];
901d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (ch == '[' || ch == 'L') {
902d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            scavengeReference((Object **)(void *)&obj->sfields[i].value.l);
903d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
904d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
905d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge interface class objects. */
906f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (int i = 0; i < obj->interfaceCount; ++i) {
907d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        scavengeReference((Object **) &obj->interfaces[i]);
908d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
909d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
910d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
911d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
912d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Array object scavenging.
913d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
914d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic size_t scavengeArrayObject(ArrayObject *array)
915d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
9168bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeArrayObject(array=%p)", array);
917d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the class object. */
918952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(toSpaceContains(array));
919d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(array != NULL);
920d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(array->obj.clazz != NULL);
921d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference((Object **) array);
922f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t length = dvmArrayObjectSize(array);
923d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the array contents. */
924d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (IS_CLASS_FLAG_SET(array->obj.clazz, CLASS_ISOBJECTARRAY)) {
925d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        Object **contents = (Object **)array->contents;
926f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        for (size_t i = 0; i < array->length; ++i) {
927d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            scavengeReference(&contents[i]);
928d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
929d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
930d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return length;
931d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
932d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
933d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
934d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Reference object scavenging.
935d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
936d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
937952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic int getReferenceFlags(const Object *obj)
938d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
939d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    int flags;
940d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
941d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    flags = CLASS_ISREFERENCE |
942d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            CLASS_ISWEAKREFERENCE |
943d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            CLASS_ISPHANTOMREFERENCE;
944952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
945d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
946d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
947952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic int isSoftReference(const Object *obj)
948d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
949d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return getReferenceFlags(obj) == CLASS_ISREFERENCE;
950d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
951d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
952952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic int isWeakReference(const Object *obj)
953d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
954d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return getReferenceFlags(obj) & CLASS_ISWEAKREFERENCE;
955d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
956d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
957eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro#ifndef NDEBUG
958952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool isPhantomReference(const Object *obj)
959d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
960d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return getReferenceFlags(obj) & CLASS_ISPHANTOMREFERENCE;
961d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
962eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro#endif
963d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
964952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro/*
965952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * Returns true if the reference was registered with a reference queue
966952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * but has not yet been appended to it.
967952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro */
968952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic bool isReferenceEnqueuable(const Object *ref)
969d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
970952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object *queue, *queueNext;
971d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
972952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    queue = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue);
973952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    queueNext = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext);
974952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (queue == NULL || queueNext != NULL) {
975952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        /*
976952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         * There is no queue, or the reference has already
977952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         * been enqueued.  The Reference.enqueue() method
978952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         * will do nothing even if we call it.
979952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         */
980952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        return false;
981952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
982952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
983952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
984952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * We need to call enqueue(), but if we called it from
985952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * here we'd probably deadlock.  Schedule a call.
986952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
987952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    return true;
988d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
989d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
990952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro/*
991952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * Schedules a reference to be appended to its reference queue.
992952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro */
993eff0df741d2b1537cf1010328000c1369559b628Carl Shapirostatic void enqueueReference(Object *ref)
994d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
995646ba0996da817deddb509b2130a6ad432096691Carl Shapiro    assert(ref != NULL);
996952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
997952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
998646ba0996da817deddb509b2130a6ad432096691Carl Shapiro    if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
999c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("no room for any more reference operations");
1000952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        dvmAbort();
1001952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1002d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1003d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1004952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro/*
1005952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * Sets the referent field of a reference object to NULL.
1006952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro */
1007952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic void clearReference(Object *obj)
1008d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1009952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    dvmSetFieldObject(obj, gDvm.offJavaLangRefReference_referent, NULL);
1010952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro}
1011d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1012952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro/*
1013952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * Clears reference objects with white referents.
1014952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro */
1015952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirovoid clearWhiteReferences(Object **list)
1016952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro{
1017697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    size_t referentOffset, queueNextOffset;
1018952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    bool doSignal;
1019952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1020697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
1021952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    referentOffset = gDvm.offJavaLangRefReference_referent;
1022952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    doSignal = false;
1023952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    while (*list != NULL) {
1024952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        Object *ref = *list;
1025952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        JValue *field = dvmFieldPtr(ref, referentOffset);
1026952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        Object *referent = field->l;
1027697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes        *list = dvmGetFieldObject(ref, queueNextOffset);
1028697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes        dvmSetFieldObject(ref, queueNextOffset, NULL);
1029952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        assert(referent != NULL);
1030952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        if (isForward(referent->clazz)) {
1031952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            field->l = referent = getForward(referent->clazz);
1032952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            continue;
1033952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1034952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        if (fromSpaceContains(referent)) {
1035952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            /* Referent is white, clear it. */
1036952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            clearReference(ref);
1037952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            if (isReferenceEnqueuable(ref)) {
1038952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                enqueueReference(ref);
1039952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                doSignal = true;
1040952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            }
1041952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1042952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1043952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
1044952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * If we cleared a reference with a reference queue we must notify
1045952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * the heap worker to append the reference.
1046952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1047952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (doSignal) {
1048952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        dvmSignalHeapWorker(false);
1049d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1050952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(*list == NULL);
1051952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro}
1052952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1053952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro/*
1054952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * Blackens referents subject to the soft reference preservation
1055952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro * policy.
1056952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro */
1057952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirovoid preserveSoftReferences(Object **list)
1058952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro{
1059952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object *ref;
1060952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object *prev, *next;
1061697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    size_t referentOffset, queueNextOffset;
1062952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    unsigned counter;
1063952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    bool white;
1064952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1065697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
1066952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    referentOffset = gDvm.offJavaLangRefReference_referent;
1067952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    counter = 0;
1068952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    prev = next = NULL;
1069952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    ref = *list;
1070952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    while (ref != NULL) {
1071952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        JValue *field = dvmFieldPtr(ref, referentOffset);
1072952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        Object *referent = field->l;
1073697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes        next = dvmGetFieldObject(ref, queueNextOffset);
1074952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        assert(referent != NULL);
1075952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        if (isForward(referent->clazz)) {
1076952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            /* Referent is black. */
1077952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            field->l = referent = getForward(referent->clazz);
1078952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            white = false;
1079952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        } else {
1080952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            white = fromSpaceContains(referent);
1081952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1082952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        if (!white && ((++counter) & 1)) {
1083952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            /* Referent is white and biased toward saving, gray it. */
1084952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            scavengeReference((Object **)(void *)&field->l);
1085952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            white = true;
1086952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1087952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        if (white) {
1088952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            /* Referent is black, unlink it. */
1089952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            if (prev != NULL) {
1090697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes                dvmSetFieldObject(ref, queueNextOffset, NULL);
1091697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes                dvmSetFieldObject(prev, queueNextOffset, next);
1092952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            }
1093952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        } else {
1094952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            /* Referent is white, skip over it. */
1095952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            prev = ref;
1096952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1097952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        ref = next;
1098952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1099952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
1100952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * Restart the trace with the newly gray references added to the
1101952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * root set.
1102952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1103952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    scavengeBlockQueue();
1104952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro}
1105952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
11061e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid processFinalizableReferences()
1107952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro{
1108952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    HeapRefTable newPendingRefs;
1109952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
1110952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object **ref;
1111952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object **lastRef;
1112952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    size_t totalPendCount;
1113952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1114952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
1115952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * All strongly, reachable objects are black.
1116952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * Any white finalizable objects need to be finalized.
1117952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1118952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1119952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* Create a table that the new pending refs will
1120952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * be added to.
1121952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1122eff0df741d2b1537cf1010328000c1369559b628Carl Shapiro    if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
1123952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        //TODO: mark all finalizable refs and hope that
1124952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        //      we can schedule them next time.  Watch out,
1125952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        //      because we may be expecting to free up space
1126952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        //      by calling finalizers.
112760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOG_REF("no room for pending finalizations");
1128952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        dvmAbort();
1129952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1130952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1131952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
1132952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * Walk through finalizableRefs and move any white references to
1133952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * the list of new pending refs.
1134952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1135952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    totalPendCount = 0;
1136952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    while (finRefs != NULL) {
1137952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        Object **gapRef;
1138952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        size_t newPendCount = 0;
1139952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1140952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        gapRef = ref = finRefs->refs.table;
1141952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        lastRef = finRefs->refs.nextEntry;
1142952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        while (ref < lastRef) {
1143952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            if (fromSpaceContains(*ref)) {
1144952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
1145952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    //TODO: add the current table and allocate
1146952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    //      a new, smaller one.
114760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                    LOG_REF("no room for any more pending finalizations: %zd",
1148952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                            dvmHeapNumHeapRefTableEntries(&newPendingRefs));
1149952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    dvmAbort();
1150952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                }
1151952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                newPendCount++;
1152952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            } else {
1153952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                /* This ref is black, so will remain on finalizableRefs.
1154952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                 */
1155952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                if (newPendCount > 0) {
1156952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    /* Copy it up to fill the holes.
1157952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                     */
1158952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    *gapRef++ = *ref;
1159952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                } else {
1160952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    /* No holes yet; don't bother copying.
1161952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                     */
1162952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                    gapRef++;
1163952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                }
1164952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            }
1165952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro            ref++;
1166952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        }
1167952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        finRefs->refs.nextEntry = gapRef;
1168952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        //TODO: if the table is empty when we're done, free it.
1169952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        totalPendCount += newPendCount;
1170952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        finRefs = finRefs->next;
1171952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
117260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOG_REF("%zd finalizers triggered.", totalPendCount);
1173952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (totalPendCount == 0) {
1174952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        /* No objects required finalization.
1175952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         * Free the empty temporary table.
1176952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro         */
1177952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        dvmClearReferenceTable(&newPendingRefs);
1178952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        return;
1179952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1180952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1181952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* Add the new pending refs to the main list.
1182952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1183952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
1184952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro                &newPendingRefs))
1185952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    {
118660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOG_REF("can't insert new pending finalizations");
1187952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        dvmAbort();
1188952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1189952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1190952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    //TODO: try compacting the main list with a memcpy loop
1191952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1192952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* Blacken the refs we just moved; we don't want them or their
1193952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * children to get swept yet.
1194952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
1195952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    ref = newPendingRefs.table;
1196952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    lastRef = newPendingRefs.nextEntry;
1197952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(ref < lastRef);
1198952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
1199952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    while (ref < lastRef) {
1200952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        scavengeReference(ref);
1201952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        ref++;
1202952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1203952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    HPROF_CLEAR_GC_SCAN_STATE();
1204952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    scavengeBlockQueue();
1205952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    dvmSignalHeapWorker(false);
1206d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1207d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1208d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1209d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * If a reference points to from-space and has been forwarded, we snap
1210d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the pointer to its new to-space address.  If the reference points
1211d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * to an unforwarded from-space address we must enqueue the reference
1212d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * for later processing.  TODO: implement proper reference processing
1213d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * and move the referent scavenging elsewhere.
1214d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1215952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic void scavengeReferenceObject(Object *obj)
1216d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1217952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object *referent;
1218952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    Object **queue;
1219697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    size_t referentOffset, queueNextOffset;
1220952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
1221d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj != NULL);
12228bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeReferenceObject(obj=%p),'%s'", obj, obj->clazz->descriptor);
12232396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    scavengeDataObject(obj);
1224952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    referentOffset = gDvm.offJavaLangRefReference_referent;
1225952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    referent = dvmGetFieldObject(obj, referentOffset);
1226952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (referent == NULL || toSpaceContains(referent)) {
1227952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        return;
1228952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    }
1229952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (isSoftReference(obj)) {
1230952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        queue = &gDvm.gcHeap->softReferences;
1231952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    } else if (isWeakReference(obj)) {
1232952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        queue = &gDvm.gcHeap->weakReferences;
1233952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    } else {
1234952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        assert(isPhantomReference(obj));
1235952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        queue = &gDvm.gcHeap->phantomReferences;
1236d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1237697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
1238697b5a942503b14fcd537d528edfc05460f144ebBarry Hayes    dvmSetFieldObject(obj, queueNextOffset, *queue);
1239952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    *queue = obj;
12408bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeReferenceObject: enqueueing %p", obj);
1241d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1242d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1243d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1244d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Data object scavenging.
1245d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1246952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapirostatic void scavengeDataObject(Object *obj)
1247d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
12488bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_SCAV("scavengeDataObject(obj=%p)", obj);
1249d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj != NULL);
1250952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(obj->clazz != NULL);
1251952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(obj->clazz->objectSize != 0);
1252952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(toSpaceContains(obj));
1253d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge the class object. */
1254f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    ClassObject *clazz = obj->clazz;
1255d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference((Object **) obj);
1256d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Scavenge instance fields. */
1257d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (clazz->refOffsets != CLASS_WALK_SUPER) {
1258d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size_t refOffsets = clazz->refOffsets;
1259d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        while (refOffsets != 0) {
1260d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            size_t rshift = CLZ(refOffsets);
1261d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
1262d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            Object **ref = (Object **)((u1 *)obj + offset);
1263d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            scavengeReference(ref);
1264d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
1265d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1266d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
1267d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        for (; clazz != NULL; clazz = clazz->super) {
1268d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            InstField *field = clazz->ifields;
1269f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro            for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
1270d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                size_t offset = field->byteOffset;
1271d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                Object **ref = (Object **)((u1 *)obj + offset);
1272d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                scavengeReference(ref);
1273d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1274d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1275d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
12762396fda0f5907178632a14d70a94257023e33d42Carl Shapiro}
12772396fda0f5907178632a14d70a94257023e33d42Carl Shapiro
12782396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic Object *transportObject(const Object *fromObj)
12792396fda0f5907178632a14d70a94257023e33d42Carl Shapiro{
12802396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    Object *toObj;
12812396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    size_t allocSize, copySize;
12822396fda0f5907178632a14d70a94257023e33d42Carl Shapiro
12838bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_TRAN("transportObject(fromObj=%p) allocBlocks=%zu",
12842396fda0f5907178632a14d70a94257023e33d42Carl Shapiro                  fromObj,
12852396fda0f5907178632a14d70a94257023e33d42Carl Shapiro                  gDvm.gcHeap->heapSource->allocBlocks);
12862396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(fromObj != NULL);
1287952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(fromSpaceContains(fromObj));
12882396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    allocSize = copySize = objectSize(fromObj);
12892396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (LW_HASH_STATE(fromObj->lock) != LW_HASH_STATE_UNHASHED) {
12902396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        /*
12912396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * The object has been hashed or hashed and moved.  We must
12922396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * reserve an additional word for a hash code.
12932396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         */
12942396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        allocSize += sizeof(u4);
12952396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    }
12962396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
12972396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        /*
12982396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * The object has its hash code allocated.  Ensure the hash
12992396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * code is copied along with the instance data.
13002396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         */
13012396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        copySize += sizeof(u4);
13022396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    }
13032396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    /* TODO(cshapiro): don't copy, re-map large data objects. */
13042396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(copySize <= allocSize);
13052396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    toObj = allocateGray(allocSize);
13062396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(toObj != NULL);
1307952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(toSpaceContains(toObj));
13082396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    memcpy(toObj, fromObj, copySize);
13092396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED) {
13102396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        /*
13112396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * The object has had its hash code exposed.  Append it to the
13122396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         * instance and set a bit so we know to look for it there.
13132396fda0f5907178632a14d70a94257023e33d42Carl Shapiro         */
13142396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        *(u4 *)(((char *)toObj) + copySize) = (u4)fromObj >> 3;
13152396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        toObj->lock |= LW_HASH_STATE_HASHED_AND_MOVED << LW_HASH_STATE_SHIFT;
13162396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    }
13178bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_TRAN("transportObject: from %p/%zu to %p/%zu (%zu,%zu) %s",
13188bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro             fromObj, addressToBlock(gDvm.gcHeap->heapSource,fromObj),
13198bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro             toObj, addressToBlock(gDvm.gcHeap->heapSource,toObj),
13208bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro             copySize, allocSize, copySize < allocSize ? "DIFFERENT" : "");
13212396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    return toObj;
1322d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1323d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1324d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1325d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Generic reference scavenging.
1326d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1327d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1328d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1329d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Given a reference to an object, the scavenge routine will gray the
1330d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * reference.  Any objects pointed to by the scavenger object will be
1331d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * transported to new space and a forwarding pointer will be installed
1332d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * in the header of the object.
1333d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1334d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1335d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1336d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Blacken the given pointer.  If the pointer is in from space, it is
1337d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * transported to new space.  If the object has a forwarding pointer
1338d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * installed it has already been transported and the referent is
1339d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * snapped to the new address.
1340d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
13412396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic void scavengeReference(Object **obj)
1342d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1343d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    ClassObject *clazz;
13442396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    Object *fromObj, *toObj;
1345d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1346d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj);
1347d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
13482396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (*obj == NULL) return;
1349d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1350d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(dvmIsValidObject(*obj));
1351d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1352d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* The entire block is black. */
1353952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    if (toSpaceContains(*obj)) {
13548bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        LOG_SCAV("scavengeReference skipping pinned object @ %p", *obj);
13552396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        return;
1356d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
13578bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeReference(*obj=%p)", *obj);
1358d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1359952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(fromSpaceContains(*obj));
1360d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1361d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    clazz = (*obj)->clazz;
1362d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1363d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (isForward(clazz)) {
13648bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        // LOG_SCAV("forwarding %p @ %p to %p", *obj, obj, (void *)((uintptr_t)clazz & ~0x1));
1365d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        *obj = (Object *)getForward(clazz);
13662396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        return;
13672396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    }
13682396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    fromObj = *obj;
13692396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (clazz == NULL) {
13708bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        // LOG_SCAV("scavangeReference %p has a NULL class object", fromObj);
1371d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(!"implemented");
13722396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        toObj = NULL;
1373d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
13742396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        toObj = transportObject(fromObj);
1375d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
13762396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    setForward(toObj, fromObj);
13772396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    *obj = (Object *)toObj;
1378d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1379d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1380d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1381d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Generic object scavenging.
1382d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
13832396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic void scavengeObject(Object *obj)
1384d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1385d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    ClassObject *clazz;
1386d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1387d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(obj != NULL);
1388952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(obj->clazz != NULL);
1389952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    assert(!((uintptr_t)obj->clazz & 0x1));
1390d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    clazz = obj->clazz;
1391c6d2470eec726ae0ad95e4fd2d9d7da7cb2cdcbaDan Bornstein    if (dvmIsTheClassClass(clazz)) {
13922396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        scavengeClassObject((ClassObject *)obj);
1393d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
13942396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        scavengeArrayObject((ArrayObject *)obj);
1395d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
1396952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        scavengeReferenceObject(obj);
1397d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
1398952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        scavengeDataObject(obj);
1399d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1400d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1401d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1402d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1403d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * External root scavenging routines.
1404d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1405d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1406d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void pinHashTableEntries(HashTable *table)
1407d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
14088bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN(">>> pinHashTableEntries(table=%p)", table);
1409d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (table == NULL) {
1410d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return;
1411d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1412d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableLock(table);
1413f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (int i = 0; i < table->tableSize; ++i) {
1414f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        HashEntry *entry = &table->pEntries[i];
1415f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        void *obj = entry->data;
1416d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (obj == NULL || obj == HASH_TOMBSTONE) {
1417d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
1418d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1419d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        pinObject(entry->data);
1420d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1421d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableUnlock(table);
14228bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN("<<< pinHashTableEntries(table=%p)", table);
1423d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1424d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
14251e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void pinPrimitiveClasses()
1426d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1427f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t length = ARRAYSIZE(gDvm.primitiveClass);
1428f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < length; i++) {
1429d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (gDvm.primitiveClass[i] != NULL) {
1430d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            pinObject((Object *)gDvm.primitiveClass[i]);
1431d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1432d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1433d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1434d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1435d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1436d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Scavenge interned strings.  Permanent interned strings will have
1437d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * been pinned and are therefore ignored.  Non-permanent strings that
1438d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * have been forwarded are snapped.  All other entries are removed.
1439d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
14401e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void scavengeInternedStrings()
1441d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1442f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HashTable *table = gDvm.internedStrings;
1443d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (table == NULL) {
1444d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return;
1445d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1446d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableLock(table);
1447f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (int i = 0; i < table->tableSize; ++i) {
1448f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        HashEntry *entry = &table->pEntries[i];
1449f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        Object *obj = (Object *)entry->data;
1450d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (obj == NULL || obj == HASH_TOMBSTONE) {
1451d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
1452d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        } else if (!isPermanentString((StringObject *)obj)) {
14538bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            // LOG_SCAV("entry->data=%p", entry->data);
14548bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            LOG_SCAV(">>> string obj=%p", entry->data);
1455d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* TODO(cshapiro): detach white string objects */
1456d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            scavengeReference((Object **)(void *)&entry->data);
14578bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            LOG_SCAV("<<< string obj=%p", entry->data);
1458d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1459d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1460d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableUnlock(table);
1461d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1462d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
14631e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void pinInternedStrings()
1464d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1465f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HashTable *table = gDvm.internedStrings;
1466d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (table == NULL) {
1467d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        return;
1468d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1469d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableLock(table);
1470f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (int i = 0; i < table->tableSize; ++i) {
1471f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        HashEntry *entry = &table->pEntries[i];
1472f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro        Object *obj = (Object *)entry->data;
1473d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (obj == NULL || obj == HASH_TOMBSTONE) {
1474d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
1475d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        } else if (isPermanentString((StringObject *)obj)) {
1476d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            obj = (Object *)getPermanentString((StringObject*)obj);
14778bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            LOG_PROM(">>> pin string obj=%p", obj);
1478d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            pinObject(obj);
14798bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            LOG_PROM("<<< pin string obj=%p", obj);
1480d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1481d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     }
1482d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHashTableUnlock(table);
1483d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1484d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1485d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1486d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * At present, reference tables contain references that must not be
1487d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * moved by the collector.  Instead of scavenging each reference in
1488d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the table we pin each referenced object.
1489d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1490583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapirostatic void pinReferenceTable(const ReferenceTable *table)
1491d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1492d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(table != NULL);
1493d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(table->table != NULL);
1494d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(table->nextEntry != NULL);
1495f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (Object **entry = table->table; entry < table->nextEntry; ++entry) {
1496d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(entry != NULL);
1497d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert(!isForward(*entry));
1498d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        pinObject(*entry);
1499d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1500d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1501d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1502646ba0996da817deddb509b2130a6ad432096691Carl Shapirostatic void scavengeLargeHeapRefTable(LargeHeapRefTable *table)
1503d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
15047800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    for (; table != NULL; table = table->next) {
15057800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        Object **ref = table->refs.table;
15067800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        for (; ref < table->refs.nextEntry; ++ref) {
1507646ba0996da817deddb509b2130a6ad432096691Carl Shapiro            scavengeReference(ref);
15087800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro        }
15097800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro    }
15107800c097fe06c046a1f6bed8650dd546d7b7a886Carl Shapiro}
1511d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1512d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/* This code was copied from Thread.c */
1513d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void scavengeThreadStack(Thread *thread)
1514d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1515d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    const u4 *framePtr;
1516d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#if WITH_EXTRA_GC_CHECKS > 1
1517d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    bool first = true;
1518d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1519d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
152030bc0d46ae730d78c42c39cfa56a59ba3025380bbuzbee    framePtr = (const u4 *)thread->interpSave.curFrame;
1521d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (framePtr != NULL) {
1522d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        const StackSaveArea *saveArea;
1523d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        const Method *method;
1524d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1525d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        saveArea = SAVEAREA_FROM_FP(framePtr);
1526d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        method = saveArea->method;
1527583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        if (method != NULL && !dvmIsNativeMethod(method)) {
1528d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#ifdef COUNT_PRECISE_METHODS
1529d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* the GC is running, so no lock required */
1530d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
153160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                LOG_SCAV("PGC: added %s.%s %p",
15328bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                             method->clazz->descriptor, method->name, method);
1533d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1534d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#if WITH_EXTRA_GC_CHECKS > 1
1535d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /*
1536d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * May also want to enable the memset() in the "invokeMethod"
1537d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * goto target in the portable interpreter.  That sets the stack
1538d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * to a pattern that makes referring to uninitialized data
1539d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             * very obvious.
1540d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro             */
1541d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1542d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            if (first) {
1543d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /*
1544d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * First frame, isn't native, check the "alternate" saved PC
1545d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * as a sanity check.
1546d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1547d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * It seems like we could check the second frame if the first
1548d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * is native, since the PCs should be the same.  It turns out
1549d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * this doesn't always work.  The problem is that we could
1550d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * have calls in the sequence:
1551d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *   interp method #2
1552d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *   native method
1553d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *   interp method #1
1554d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1555d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * and then GC while in the native method after returning
1556d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * from interp method #2.  The currentPc on the stack is
1557d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * for interp method #1, but thread->currentPc2 is still
1558d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * set for the last thing interp method #2 did.
1559d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1560d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * This can also happen in normal execution:
1561d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * - sget-object on not-yet-loaded class
1562d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * - class init updates currentPc2
1563d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * - static field init is handled by parsing annotations;
1564d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *   static String init requires creation of a String object,
1565d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *   which can cause a GC
1566d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1567d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * Essentially, any pattern that involves executing
1568d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * interpreted code and then causes an allocation without
1569d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * executing instructions in the original method will hit
1570d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * this.  These are rare enough that the test still has
1571d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * some value.
1572d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 */
1573d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                if (saveArea->xtra.currentPc != thread->currentPc2) {
1574e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block                    ALOGW("PGC: savedPC(%p) != current PC(%p), %s.%s ins=%p",
1575d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        saveArea->xtra.currentPc, thread->currentPc2,
1576d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        method->clazz->descriptor, method->name, method->insns);
1577d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    if (saveArea->xtra.currentPc != NULL)
1578c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                        ALOGE("  pc inst = 0x%04x", *saveArea->xtra.currentPc);
1579d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    if (thread->currentPc2 != NULL)
1580c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                        ALOGE("  pc2 inst = 0x%04x", *thread->currentPc2);
1581d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    dvmDumpThread(thread, false);
1582d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                }
1583d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            } else {
1584d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /*
1585d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * It's unusual, but not impossible, for a non-first frame
1586d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * to be at something other than a method invocation.  For
1587d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * example, if we do a new-instance on a nonexistent class,
1588d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * we'll have a lot of class loader activity on the stack
1589d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * above the frame with the "new" operation.  Could also
1590d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * happen while we initialize a Throwable when an instruction
1591d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * fails.
1592d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1593d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * So there's not much we can do here to verify the PC,
1594d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * except to verify that it's a GC point.
1595d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 */
1596d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1597d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            assert(saveArea->xtra.currentPc != NULL);
1598d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1599d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1600d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            const RegisterMap* pMap;
1601d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            const u1* regVector;
1602d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1603d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            Method* nonConstMethod = (Method*) method;  // quiet gcc
1604d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            pMap = dvmGetExpandedRegisterMap(nonConstMethod);
1605d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
160660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            //LOG_SCAV("PGC: %s.%s", method->clazz->descriptor, method->name);
1607d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1608d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            if (pMap != NULL) {
1609d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /* found map, get registers for this address */
1610d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                int addr = saveArea->xtra.currentPc - method->insns;
1611d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                regVector = dvmRegisterMapGetLine(pMap, addr);
1612d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /*
1613d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                if (regVector == NULL) {
161460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                    LOG_SCAV("PGC: map but no entry for %s.%s addr=0x%04x",
16158bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                                 method->clazz->descriptor, method->name, addr);
1616d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                } else {
161760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                    LOG_SCAV("PGC: found map for %s.%s 0x%04x (t=%d)",
16188bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                                 method->clazz->descriptor, method->name, addr,
16198bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                                 thread->threadId);
1620d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                }
1621d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                */
1622d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            } else {
1623d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /*
1624d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * No map found.  If precise GC is disabled this is
1625d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * expected -- we don't create pointers to the map data even
1626d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * if it's present -- but if it's enabled it means we're
1627d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * unexpectedly falling back on a conservative scan, so it's
1628d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * worth yelling a little.
1629d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 */
1630d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                if (gDvm.preciseGc) {
163160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                    LOG_SCAV("PGC: no map for %s.%s", method->clazz->descriptor, method->name);
1632d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                }
1633d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                regVector = NULL;
1634d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1635d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            if (regVector == NULL) {
163688b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                /*
163788b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                 * There are no roots to scavenge.  Skip over the entire frame.
163888b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                 */
163988b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                framePtr += method->registersSize;
1640d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            } else {
1641d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                /*
1642d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * Precise scan.  v0 is at the lowest address on the
1643d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * interpreted stack, and is the first bit in the register
1644d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * vector, so we can walk through the register map and
1645d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * memory in the same direction.
1646d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 *
1647d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 * A '1' bit indicates a live reference.
1648d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 */
1649d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                u2 bits = 1 << 1;
1650f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro                for (int i = method->registersSize - 1; i >= 0; i--) {
1651d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    u4 rval = *framePtr;
1652d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1653d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    bits >>= 1;
1654d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    if (bits == 1) {
1655d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        /* set bit 9 so we can tell when we're empty */
1656d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        bits = *regVector++ | 0x0100;
1657d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    }
1658d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1659d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    if (rval != 0 && (bits & 0x01) != 0) {
1660d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        /*
1661d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                         * Non-null, register marked as live reference.  This
1662d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                         * should always be a valid object.
1663d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                         */
1664d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#if WITH_EXTRA_GC_CHECKS > 0
1665d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        if ((rval & 0x3) != 0 || !dvmIsValidObject((Object*) rval)) {
1666d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                            /* this is very bad */
1667c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                            ALOGE("PGC: invalid ref in reg %d: 0x%08x",
1668d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                                method->registersSize-1 - i, rval);
1669d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        } else
1670d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1671d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        {
1672d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
16738bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                            // LOG_SCAV("stack reference %u@%p", *framePtr, framePtr);
1674d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                            /* dvmMarkObjectNonNull((Object *)rval); */
1675d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                            scavengeReference((Object **) framePtr);
1676d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        }
1677d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    } else {
1678d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        /*
1679d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                         * Null or non-reference, do nothing at all.
1680d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                         */
1681d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#if WITH_EXTRA_GC_CHECKS > 1
1682d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        if (dvmIsValidObject((Object*) rval)) {
1683d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                            /* this is normal, but we feel chatty */
1684062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                            ALOGD("PGC: ignoring valid ref in reg %d: 0x%08x",
1685d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                                 method->registersSize-1 - i, rval);
1686d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                        }
1687d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1688d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    }
1689d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                    ++framePtr;
1690d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                }
1691d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                dvmReleaseRegisterMapLine(pMap, regVector);
1692d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1693d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1694952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro        /* else this is a break frame and there is nothing to gray, or
1695d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         * this is a native method and the registers are just the "ins",
1696d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         * copied from various registers in the caller's set.
1697d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         */
1698d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1699d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#if WITH_EXTRA_GC_CHECKS > 1
1700d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        first = false;
1701d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro#endif
1702d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1703d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        /* Don't fall into an infinite loop if things get corrupted.
1704d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro         */
1705d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
1706d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro               saveArea->prevFrame == NULL);
1707d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        framePtr = saveArea->prevFrame;
1708d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1709d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1710d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1711d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void scavengeThread(Thread *thread)
1712d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
17138bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_SCAV("scavengeThread(thread=%p)", thread);
1714d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
17158bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_SCAV("Scavenging threadObj=%p", thread->threadObj);
1716d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&thread->threadObj);
1717d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
17188bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_SCAV("Scavenging exception=%p", thread->exception);
1719d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&thread->exception);
1720d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1721d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeThreadStack(thread);
1722d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1723d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
17241e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void scavengeThreadList()
1725d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1726d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    Thread *thread;
1727d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1728d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmLockThreadList(dvmThreadSelf());
1729d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    thread = gDvm.threadList;
1730d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (thread) {
1731d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        scavengeThread(thread);
1732d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        thread = thread->next;
1733d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1734d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmUnlockThreadList();
1735d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1736d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
173788b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapirostatic void pinThreadStack(const Thread *thread)
1738583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro{
1739583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    const u4 *framePtr;
1740583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    const StackSaveArea *saveArea;
174188b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro    Method *method;
1742583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    const char *shorty;
1743583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    Object *obj;
1744583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro
1745583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    saveArea = NULL;
174630bc0d46ae730d78c42c39cfa56a59ba3025380bbuzbee    framePtr = (const u4 *)thread->interpSave.curFrame;
1747583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
1748583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        saveArea = SAVEAREA_FROM_FP(framePtr);
174988b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro        method = (Method *)saveArea->method;
1750583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        if (method != NULL && dvmIsNativeMethod(method)) {
1751583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            /*
175288b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro             * This is native method, pin its arguments.
175388b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro             *
1754952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro             * For purposes of graying references, we don't need to do
1755583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * anything here, because all of the native "ins" were copied
1756583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * from registers in the caller's stack frame and won't be
1757583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * changed (an interpreted method can freely use registers
1758583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * with parameters like any other register, but natives don't
1759583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * work that way).
1760583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             *
1761583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * However, we need to ensure that references visible to
1762583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * native methods don't move around.  We can do a precise scan
1763583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             * of the arguments by examining the method signature.
1764583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro             */
176560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOG_PIN("+++ native scan %s.%s",
17668bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                    method->clazz->descriptor, method->name);
1767583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            assert(method->registersSize == method->insSize);
1768583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            if (!dvmIsStaticMethod(method)) {
1769583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                /* grab the "this" pointer */
1770583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                obj = (Object *)*framePtr++;
1771583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                if (obj == NULL) {
1772583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    /*
1773583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     * This can happen for the "fake" entry frame inserted
1774583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     * for threads created outside the VM.  There's no actual
1775583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     * call so there's no object.  If we changed the fake
1776583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     * entry method to be declared "static" then this
1777583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     * situation should never occur.
1778583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                     */
1779583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                } else {
1780583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    assert(dvmIsValidObject(obj));
1781583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    pinObject(obj);
1782583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                }
1783583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            }
1784583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            shorty = method->shorty+1;      // skip return value
1785f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro            for (int i = method->registersSize - 1; i >= 0; i--, framePtr++) {
1786583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                switch (*shorty++) {
1787583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                case 'L':
1788583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    obj = (Object *)*framePtr;
1789583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    if (obj != NULL) {
1790583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                        assert(dvmIsValidObject(obj));
1791583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                        pinObject(obj);
1792583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    }
1793583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    break;
1794583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                case 'D':
1795583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                case 'J':
1796583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    framePtr++;
1797583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    break;
1798583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                default:
1799583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    /* 32-bit non-reference value */
1800583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    obj = (Object *)*framePtr;          // debug, remove
1801583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    if (dvmIsValidObject(obj)) {        // debug, remove
1802583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                        /* if we see a lot of these, our scan might be off */
180360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                        LOG_PIN("+++ did NOT pin obj %p", obj);
1804583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    }
1805583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                    break;
1806583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro                }
1807583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro            }
180888b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro        } else if (method != NULL && !dvmIsNativeMethod(method)) {
180988b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
181088b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            const u1* regVector = NULL;
181188b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro
18124308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("conservative : %s.%s", method->clazz->descriptor, method->name);
181388b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro
181488b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            if (pMap != NULL) {
181588b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                int addr = saveArea->xtra.currentPc - method->insns;
181688b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                regVector = dvmRegisterMapGetLine(pMap, addr);
181788b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            }
181888b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            if (regVector == NULL) {
181988b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                /*
182088b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                 * No register info for this frame, conservatively pin.
182188b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                 */
1822f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro                for (int i = 0; i < method->registersSize; ++i) {
182388b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                    u4 regValue = framePtr[i];
182488b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                    if (regValue != 0 && (regValue & 0x3) == 0 && dvmIsValidObject((Object *)regValue)) {
182588b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                        pinObject((Object *)regValue);
182688b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                    }
182788b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro                }
182888b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro            }
1829583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        }
1830583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        /*
1831583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro         * Don't fall into an infinite loop if things get corrupted.
1832583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro         */
1833583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
1834583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro               saveArea->prevFrame == NULL);
1835583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro    }
1836583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro}
1837583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro
1838583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapirostatic void pinThread(const Thread *thread)
1839d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1840d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(thread != NULL);
18418bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN("pinThread(thread=%p)", thread);
1842d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
18438bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN("Pin native method arguments");
184488b0035c26d6281fd6f07e35b52433c5b410ed26Carl Shapiro    pinThreadStack(thread);
1845583d64c0b51ea2036bf235281adb85cc0d67ae92Carl Shapiro
18468bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN("Pin internalLocalRefTable");
1847d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinReferenceTable(&thread->internalLocalRefTable);
1848d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
18498bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_PIN("Pin jniLocalRefTable");
1850d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinReferenceTable(&thread->jniLocalRefTable);
1851d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1852d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Can the check be pushed into the promote routine? */
1853d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    if (thread->jniMonitorRefTable.table) {
18548bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        LOG_PIN("Pin jniMonitorRefTable");
1855d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        pinReferenceTable(&thread->jniMonitorRefTable);
1856d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1857d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1858d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
18591e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void pinThreadList()
1860d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1861d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    Thread *thread;
1862d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1863d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmLockThreadList(dvmThreadSelf());
1864d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    thread = gDvm.threadList;
1865d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (thread) {
1866d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        pinThread(thread);
1867d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        thread = thread->next;
1868d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1869d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmUnlockThreadList();
1870d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1871d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1872d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1873d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Heap block scavenging.
1874d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1875d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1876d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
1877d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Scavenge objects in the current block.  Scavenging terminates when
1878d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * the pointer reaches the highest address in the block or when a run
1879d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * of zero words that continues to the highest address is reached.
1880d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
1881d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void scavengeBlock(HeapSource *heapSource, size_t block)
1882d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1883d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *cursor;
1884d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *end;
1885d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t size;
1886d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
18878bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeBlock(heapSource=%p,block=%zu)", heapSource, block);
1888d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1889d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
1890d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(block < heapSource->totalBlocks);
1891d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
1892d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1893d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    cursor = blockToAddress(heapSource, block);
1894d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    end = cursor + BLOCK_SIZE;
18958bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("scavengeBlock start=%p, end=%p", cursor, end);
1896d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1897d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Parse and scavenge the current block. */
1898d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size = 0;
1899d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (cursor < end) {
1900d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        u4 word = *(u4 *)cursor;
1901d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (word != 0) {
19022396fda0f5907178632a14d70a94257023e33d42Carl Shapiro            scavengeObject((Object *)cursor);
19032396fda0f5907178632a14d70a94257023e33d42Carl Shapiro            size = objectSize((Object *)cursor);
1904d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            size = alignUp(size, ALLOC_ALIGNMENT);
1905d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            cursor += size;
1906d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        } else {
1907d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* Check for padding. */
1908d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            while (*(u4 *)cursor == 0) {
1909d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                cursor += 4;
1910d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                if (cursor == end) break;
1911d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1912d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* Punt if something went wrong. */
1913d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            assert(cursor == end);
1914d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1915d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1916d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1917d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
19182396fda0f5907178632a14d70a94257023e33d42Carl Shapirostatic size_t objectSize(const Object *obj)
1919d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1920d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t size;
1921d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
19222396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(obj != NULL);
19232396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    assert(obj->clazz != NULL);
1924c49db8554956f8d43eb487709bc1dccfe0496ad2Barry Hayes    if (obj->clazz == gDvm.classJavaLangClass) {
1925d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size = dvmClassObjectSize((ClassObject *)obj);
1926d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
1927d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size = dvmArrayObjectSize((ArrayObject *)obj);
1928d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    } else {
19292396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        assert(obj->clazz->objectSize != 0);
1930d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size = obj->clazz->objectSize;
1931d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
19322396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    if (LW_HASH_STATE(obj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
19332396fda0f5907178632a14d70a94257023e33d42Carl Shapiro        size += sizeof(u4);
19342396fda0f5907178632a14d70a94257023e33d42Carl Shapiro    }
1935d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return size;
1936d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1937d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1938d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void verifyBlock(HeapSource *heapSource, size_t block)
1939d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1940d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *cursor;
1941d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    u1 *end;
1942d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t size;
1943d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
19448bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_VER("verifyBlock(heapSource=%p,block=%zu)", heapSource, block);
1945d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1946d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource != NULL);
1947d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(block < heapSource->totalBlocks);
1948d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
1949d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1950d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    cursor = blockToAddress(heapSource, block);
1951d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    end = cursor + BLOCK_SIZE;
19528bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_VER("verifyBlock start=%p, end=%p", cursor, end);
1953d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1954d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Parse and scavenge the current block. */
1955d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size = 0;
1956d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (cursor < end) {
1957d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        u4 word = *(u4 *)cursor;
1958d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (word != 0) {
1959d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            dvmVerifyObject((Object *)cursor);
1960d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            size = objectSize((Object *)cursor);
1961d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            size = alignUp(size, ALLOC_ALIGNMENT);
1962d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            cursor += size;
1963d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        } else {
1964d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* Check for padding. */
1965d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            while (*(unsigned long *)cursor == 0) {
1966d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                cursor += 4;
1967d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                if (cursor == end) break;
1968d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            }
1969d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            /* Punt if something went wrong. */
1970d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            assert(cursor == end);
1971d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
1972d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1973d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1974d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1975d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirostatic void describeBlockQueue(const HeapSource *heapSource)
1976d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
1977d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t block, count;
1978d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    char space;
1979d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
1980d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    block = heapSource->queueHead;
1981d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    count = 0;
19828bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV(">>> describeBlockQueue(heapSource=%p)", heapSource);
1983d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Count the number of blocks enqueued. */
1984d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (block != QUEUE_TAIL) {
1985d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        block = heapSource->blockQueue[block];
1986d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        ++count;
1987d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
19888bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("blockQueue %zu elements, enqueued %zu",
1989d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro                 count, heapSource->queueSize);
1990d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    block = heapSource->queueHead;
1991d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (block != QUEUE_TAIL) {
1992d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        space = heapSource->blockSpace[block];
19938bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        LOG_SCAV("block=%zu@%p,space=%zu", block, blockToAddress(heapSource,block), space);
1994d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        block = heapSource->blockQueue[block];
1995d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
1996d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
19978bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("<<< describeBlockQueue(heapSource=%p)", heapSource);
1998d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
1999d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2000d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
2001d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Blackens promoted objects.
2002d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
20031e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void scavengeBlockQueue()
2004d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2005d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    HeapSource *heapSource;
2006d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    size_t block;
2007d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
20088bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV(">>> scavengeBlockQueue()");
2009d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    heapSource = gDvm.gcHeap->heapSource;
2010d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    describeBlockQueue(heapSource);
2011d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    while (heapSource->queueHead != QUEUE_TAIL) {
2012d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        block = heapSource->queueHead;
201360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOG_SCAV("Dequeueing block %zu", block);
2014d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        scavengeBlock(heapSource, block);
2015d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        heapSource->queueHead = heapSource->blockQueue[block];
201660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOG_SCAV("New queue head is %zu", heapSource->queueHead);
2017d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
20188bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("<<< scavengeBlockQueue()");
2019d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2020d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2021d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
2022d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Scan the block list and verify all blocks that are marked as being
2023d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * in new space.  This should be parametrized so we can invoke this
2024d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * routine outside of the context of a collection.
2025d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
20261e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void verifyNewSpace()
2027d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2028f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HeapSource *heapSource = gDvm.gcHeap->heapSource;
2029f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    size_t c0 = 0, c1 = 0, c2 = 0, c7 = 0;
2030f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
2031d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        switch (heapSource->blockSpace[i]) {
2032d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        case BLOCK_FREE: ++c0; break;
2033d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        case BLOCK_TO_SPACE: ++c1; break;
2034d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        case BLOCK_FROM_SPACE: ++c2; break;
2035d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        case BLOCK_CONTINUED: ++c7; break;
2036d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        default: assert(!"reached");
2037d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
2038d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
20398bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_VER("Block Demographics: "
20408bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            "Free=%zu,ToSpace=%zu,FromSpace=%zu,Continued=%zu",
20418bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro            c0, c1, c2, c7);
2042f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
2043d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        if (heapSource->blockSpace[i] != BLOCK_TO_SPACE) {
2044d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro            continue;
2045d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        }
2046d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        verifyBlock(heapSource, i);
2047d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
2048d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2049d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
20501e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid describeHeap()
2051d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2052f9fa8c14c7ef87b4318d606bfc5132df7b77b17cCarl Shapiro    HeapSource *heapSource = gDvm.gcHeap->heapSource;
2053d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    describeBlocks(heapSource);
2054d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2055d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2056d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
2057d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The collection interface.  Collection has a few distinct phases.
2058d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * The first is flipping AKA condemning AKA whitening the heap.  The
2059d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * second is to promote all objects which are pointed to by pinned or
2060d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * ambiguous references.  The third phase is tracing from the stacks,
2061d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * registers and various globals.  Lastly, a verification of the heap
2062d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * is performed.  The last phase should be optional.
2063d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
20641e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmScavengeRoots()  /* Needs a new name badly */
2065d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2066d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    GcHeap *gcHeap;
2067d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2068d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    {
2069d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size_t alloc, unused, total;
2070d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2071d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        room(&alloc, &unused, &total);
20728bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        LOG_SCAV("BEFORE GC: %zu alloc, %zu free, %zu total.",
20738bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro                     alloc, unused, total);
2074d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
2075d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2076d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    gcHeap = gDvm.gcHeap;
2077d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmHeapSourceFlip();
2078d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2079d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
2080d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Promote blocks with stationary objects.
2081d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
2082d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinThreadList();
2083d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinReferenceTable(&gDvm.jniGlobalRefTable);
2084d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinReferenceTable(&gDvm.jniPinRefTable);
2085d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinHashTableEntries(gDvm.loadedClasses);
2086427bf463f1afa080908bbed7319f585cce9e6db2Carl Shapiro    pinHashTableEntries(gDvm.dbgRegistry);
2087d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinPrimitiveClasses();
2088d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    pinInternedStrings();
2089d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2090d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    // describeBlocks(gcHeap->heapSource);
2091d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2092d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
2093d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Create first, open new-space page right here.
2094d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
2095d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2096d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* Reset allocation to an unallocated block. */
2097d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    gDvm.gcHeap->heapSource->allocPtr = allocateBlocks(gDvm.gcHeap->heapSource, 1);
2098d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    gDvm.gcHeap->heapSource->allocLimit = gDvm.gcHeap->heapSource->allocPtr + BLOCK_SIZE;
2099d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
2100d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Hack: promote the empty block allocated above.  If the
2101d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * promotions that occurred above did not actually gray any
2102d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * objects, the block queue may be empty.  We must force a
2103d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * promotion to be safe.
2104d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
2105d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    promoteBlockByAddr(gDvm.gcHeap->heapSource, gDvm.gcHeap->heapSource->allocPtr);
2106d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2107d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
2108d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Scavenge blocks and relocate movable objects.
2109d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
2110d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21118bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("Scavenging gDvm.threadList");
2112d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeThreadList();
2113d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21148bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("Scavenging gDvm.gcHeap->referenceOperations");
2115646ba0996da817deddb509b2130a6ad432096691Carl Shapiro    scavengeLargeHeapRefTable(gcHeap->referenceOperations);
2116d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21178bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("Scavenging gDvm.gcHeap->pendingFinalizationRefs");
2118646ba0996da817deddb509b2130a6ad432096691Carl Shapiro    scavengeLargeHeapRefTable(gcHeap->pendingFinalizationRefs);
2119d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21208bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("Scavenging random global stuff");
2121d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&gDvm.outOfMemoryObj);
2122d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&gDvm.internalErrorObj);
2123d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeReference(&gDvm.noClassDefFoundErrorObj);
2124d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21258bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    // LOG_SCAV("Scavenging gDvm.internedString");
2126d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeInternedStrings();
2127d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21288bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("Root scavenge has completed.");
2129d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2130d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    scavengeBlockQueue();
2131d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
213206d3da57d53d63bd49f14bffbd54972819c9b79cDan Bornstein    // LOG_SCAV("Re-snap global class pointers.");
213306d3da57d53d63bd49f14bffbd54972819c9b79cDan Bornstein    // scavengeGlobals();
2134d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
21358bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_SCAV("New space scavenge has completed.");
2136d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2137d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /*
2138952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     * Process reference objects in strength order.
2139952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro     */
2140952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21418bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Processing soft references...");
2142952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    preserveSoftReferences(&gDvm.gcHeap->softReferences);
2143952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    clearWhiteReferences(&gDvm.gcHeap->softReferences);
2144952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21458bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Processing weak references...");
2146952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    clearWhiteReferences(&gDvm.gcHeap->weakReferences);
2147952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21488bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Finding finalizations...");
2149952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    processFinalizableReferences();
2150952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21518bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Processing f-reachable soft references...");
2152952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    clearWhiteReferences(&gDvm.gcHeap->softReferences);
2153952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21548bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Processing f-reachable weak references...");
2155952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    clearWhiteReferences(&gDvm.gcHeap->weakReferences);
2156952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
21578bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro    LOG_REF("Processing phantom references...");
2158952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    clearWhiteReferences(&gDvm.gcHeap->phantomReferences);
2159952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro
2160952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /*
2161d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     * Verify the stack and heap.
2162d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro     */
2163f571825e42a0daa957b99f8cf7598f517b504fa3Carl Shapiro    dvmVerifyRoots();
2164d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    verifyNewSpace();
2165d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2166d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    //describeBlocks(gcHeap->heapSource);
2167d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2168d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    clearFromSpace(gcHeap->heapSource);
2169d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2170d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    {
2171d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        size_t alloc, rem, total;
2172d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2173d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro        room(&alloc, &rem, &total);
21748bb533e726c477d4982b30d01d19c0cda5fa7fb6Carl Shapiro        LOG_SCAV("AFTER GC: %zu alloc, %zu free, %zu total.", alloc, rem, total);
2175d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    }
2176d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2177d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2178d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro/*
2179d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro * Interface compatibility routines.
2180d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro */
2181d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2182d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmClearWhiteRefs(Object **list)
2183d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2184952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* do nothing */
2185d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(*list == NULL);
2186d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2187d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2188d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmHandleSoftRefs(Object **list)
2189d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2190952e84a2716643a7c70dc8370b49db12ef9cce4eCarl Shapiro    /* do nothing */
2191d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    assert(*list == NULL);
2192d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2193d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2194d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirobool dvmHeapBeginMarkStep(GcMode mode)
2195d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2196d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
2197d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    return true;
2198d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2199d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
22001e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapFinishMarkStep()
2201d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2202d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
2203d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2204d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
22051e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapMarkRootSet()
2206d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2207d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
2208d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2209d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
22101e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapScanMarkedObjects()
2211d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2212d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    dvmScavengeRoots();
2213d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2214d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
22151e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapScheduleFinalizations()
2216d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2217d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
2218d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2219d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
2220d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapirovoid dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
2221d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro{
2222703a2f3f1acc3ecc23d37970af2638463587a40fCarl Shapiro    *numFreed = 0;
2223703a2f3f1acc3ecc23d37970af2638463587a40fCarl Shapiro    *sizeFreed = 0;
2224d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro    /* do nothing */
2225d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro}
2226d28668cf8740d1f913b4e9140a8c685013c1ad18Carl Shapiro
22271e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmMarkDirtyObjects()
2228791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro{
2229791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro    assert(!"implemented");
2230791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro}
2231791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro
22321e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapSourceThreadShutdown()
2233791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro{
2234791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro    /* do nothing */
2235791802c9408e6506d8382bee74c250d169c88d2aCarl Shapiro}
2236