Add a bit-map encoding of Object-reference field offsets to ClassObject.
Class.c populates a new field with a bit for each of the first 32 instance
fields, to show if it is a reference or not, and an escape value if there is a
reference field beyond 32.
The GC uses the encoded bitmap -- if available -- to extract Object refererences
from DataObjects.
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index a5d42eb..e00fae7 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -181,6 +181,8 @@
const DexField* pDexSField, StaticField* sfield);
static void loadIFieldFromDex(ClassObject* clazz,
const DexField* pDexIField, InstField* field);
+static bool precacheReferenceOffsets(ClassObject* clazz);
+static void computeRefOffsets(ClassObject* clazz);
static void freeMethodInnards(Method* meth);
static bool createVtable(ClassObject* clazz);
static bool createIftable(ClassObject* clazz);
@@ -2157,7 +2159,7 @@
/*
* Cache java.lang.ref.Reference fields and methods.
*/
-static bool precacheReferenceOffsets(ClassObject *clazz)
+static bool precacheReferenceOffsets(ClassObject* clazz)
{
Method *meth;
int i;
@@ -2256,6 +2258,51 @@
/*
+ * Set the bitmap of reference offsets, refOffsets, from the ifields
+ * list.
+ */
+static void computeRefOffsets(ClassObject* clazz)
+{
+ if (clazz->super != NULL) {
+ clazz->refOffsets = clazz->super->refOffsets;
+ } else {
+ clazz->refOffsets = 0;
+ }
+ /*
+ * If our superclass overflowed, we don't stand a chance.
+ */
+ if (clazz->refOffsets != CLASS_WALK_SUPER) {
+ InstField *f;
+ int i;
+
+ /* All of the fields that contain object references
+ * are guaranteed to be at the beginning of the ifields list.
+ */
+ f = clazz->ifields;
+ const int ifieldRefCount = clazz->ifieldRefCount;
+ for (i = 0; i < ifieldRefCount; i++) {
+ /*
+ * Note that, per the comment on struct InstField,
+ * f->byteOffset is the offset from the beginning of
+ * obj, not the offset into obj->instanceData.
+ */
+ assert(f->byteOffset >= CLASS_SMALLEST_OFFSET);
+ assert((f->byteOffset & (CLASS_OFFSET_ALIGNMENT - 1)) == 0);
+ if (CLASS_CAN_ENCODE_OFFSET(f->byteOffset)) {
+ u4 newBit = CLASS_BIT_FROM_OFFSET(f->byteOffset);
+ assert(newBit != 0);
+ clazz->refOffsets |= newBit;
+ } else {
+ clazz->refOffsets = CLASS_WALK_SUPER;
+ break;
+ }
+ f++;
+ }
+ }
+}
+
+
+/*
* Link (prepare and resolve). Verification is deferred until later.
*
* This converts symbolic references into pointers. It's independent of
@@ -2623,6 +2670,13 @@
}
/*
+ * Compact the offsets the GC has to examine into a bitmap, if
+ * possible. (This has to happen after Reference.referent is
+ * massaged in precacheReferenceOffsets.)
+ */
+ computeRefOffsets(clazz);
+
+ /*
* Done!
*/
if (IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED))
@@ -4249,44 +4303,6 @@
dvmCallMethod(self, method, NULL, &unused);
}
- /* Set the bitmap of reference offsets. Except for class Object,
- * start with the superclass offsets.
- */
- if (clazz->super != NULL) {
- clazz->refOffsets = clazz->super->refOffsets;
- } else {
- clazz->refOffsets = 0;
- }
- /*
- * If our superclass overflowed, we don't stand a chance.
- */
- if (clazz->refOffsets != CLASS_WALK_SUPER) {
- InstField *f;
- int i;
-
- /* All of the fields that contain object references
- * are guaranteed to be at the beginning of the ifields list.
- */
- f = clazz->ifields;
- for (i = 0; i < clazz->ifieldRefCount; i++) {
- /*
- * Note that, per the comment on struct InstField,
- * f->byteOffset is the offset from the beginning of
- * obj, not the offset into obj->instanceData.
- */
- assert(f->byteOffset >= CLASS_SMALLEST_OFFSET);
- assert((f->byteOffset & (CLASS_OFFSET_ALIGNMENT - 1)) == 0);
- u4 newBit = CLASS_BIT_FROM_OFFSET(f->byteOffset);
- if (newBit != 0) {
- clazz->refOffsets |= newBit;
- } else {
- clazz->refOffsets = CLASS_WALK_SUPER;
- break;
- }
- f++;
- }
- }
-
if (dvmCheckException(self)) {
/*
* We've had an exception thrown during static initialization. We
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 8c2f251..82194c3 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -148,12 +148,23 @@
#define CLASS_OFFSET_ALIGNMENT 4
#define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
/*
- * Return a single bit, or zero if the encoding can't encode the offset.
+ * Given an offset, return the bit number which would encode that offset.
+ * Local use only.
+ */
+#define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) \
+ (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
+ CLASS_OFFSET_ALIGNMENT)
+/*
+ * Is the given offset too large to be encoded?
+ */
+#define CLASS_CAN_ENCODE_OFFSET(byteOffset) \
+ (_CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) < CLASS_BITS_PER_WORD)
+/*
+ * Return a single bit, encoding the offset.
+ * Undefined if the offset is too large, as defined above.
*/
#define CLASS_BIT_FROM_OFFSET(byteOffset) \
- (CLASS_HIGH_BIT >> \
- (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
- CLASS_OFFSET_ALIGNMENT))
+ (CLASS_HIGH_BIT >> _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset))
/*
* Return an offset, given a bit number as returned from CLZ.
*/