Added some utility functions for register maps.
These should be useful for the garbage collector.
Change-Id: I9503af6338031dd8726498e11035758076530f68
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 404227d..0170ebe 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -362,12 +362,9 @@
uint8_t format_; /* enum RegisterMapFormat; MUST be first entry */
uint8_t reg_width_; /* bytes per register line, 1+ */
uint16_t num_entries_; /* number of entries */
- bool format_on_heap_; /* indicates allocation on heap */
- RegisterMapHeader(uint8_t format, uint8_t reg_width, uint16_t num_entries,
- bool format_on_heap)
- : format_(format), reg_width_(reg_width), num_entries_(num_entries),
- format_on_heap_(format_on_heap) {
+ RegisterMapHeader(uint8_t format, uint8_t reg_width, uint16_t num_entries)
+ : format_(format), reg_width_(reg_width), num_entries_(num_entries) {
}
};
@@ -395,9 +392,8 @@
}
RegisterMap(uint8_t format, uint8_t reg_width, uint16_t num_entries,
- bool format_on_heap, uint32_t data_size) {
- header_ = new RegisterMapHeader(format, reg_width, num_entries,
- format_on_heap);
+ uint32_t data_size) {
+ header_ = new RegisterMapHeader(format, reg_width, num_entries);
data_ = new uint8_t[data_size]();
needs_free_ = true;
}
@@ -561,6 +557,136 @@
return (uint32_t) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
}
+ /*
+ * Generate the register map for a method that has just been verified
+ * (i.e. we're doing this as part of verification).
+ *
+ * For type-precise determination we have all the data we need, so we
+ * just need to encode it in some clever fashion.
+ *
+ * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
+ */
+ static RegisterMap* GenerateRegisterMapV(VerifierData* vdata);
+
+ /*
+ * Get the expanded form of the register map associated with the specified
+ * method. May update the RegisterMap, possibly freeing the previous map.
+ *
+ * Returns NULL on failure (e.g. unable to expand map).
+ *
+ * NOTE: this function is not synchronized; external locking is mandatory.
+ * (This is expected to be called at GC time.)
+ */
+ static inline RegisterMap* GetExpandedRegisterMap(Method* method) {
+ if (method->GetRegisterMapHeader() == NULL ||
+ method->GetRegisterMapData() == NULL) {
+ return NULL;
+ }
+ RegisterMap* cur_map = new RegisterMap(method->GetRegisterMapHeader(),
+ method->GetRegisterMapData());
+ uint8_t format = cur_map->header_->format_;
+ if (format == kRegMapFormatCompact8 || format == kRegMapFormatCompact16) {
+ return cur_map;
+ } else {
+ return GetExpandedRegisterMapHelper(method, cur_map);
+ }
+ }
+
+ /*
+ * Get the expanded form of the register map associated with the method.
+ *
+ * If the map is already in one of the uncompressed formats, we return
+ * immediately. Otherwise, we expand the map and replace method's register
+ * map pointer, freeing it if it was allocated on the heap.
+ *
+ * NOTE: this function is not synchronized; external locking is mandatory
+ * (unless we're in the zygote, where single-threaded access is guaranteed).
+ */
+ static RegisterMap* GetExpandedRegisterMapHelper(Method* method,
+ RegisterMap* map);
+
+ /* Return the data for the specified address, or NULL if not found. */
+ static const uint8_t* RegisterMapGetLine(const RegisterMap* map, int addr);
+
+ /*
+ * Determine if the RegType value is a reference type.
+ *
+ * Ordinarily we include kRegTypeZero in the "is it a reference"
+ * check. There's no value in doing so here, because we know
+ * the register can't hold anything but zero.
+ */
+ static inline bool IsReferenceType(RegType type) {
+ return (type > kRegTypeMAX || type == kRegTypeUninit);
+ }
+
+ /* Toggle the value of the "idx"th bit in "ptr". */
+ static inline void ToggleBit(uint8_t* ptr, int idx) {
+ ptr[idx >> 3] ^= 1 << (idx & 0x07);
+ }
+
+ /*
+ * Given a line of registers, output a bit vector that indicates whether
+ * or not the register holds a reference type (which could be null).
+ *
+ * We use '1' to indicate it's a reference, '0' for anything else (numeric
+ * value, uninitialized data, merge conflict). Register 0 will be found
+ * in the low bit of the first byte.
+ */
+ static void OutputTypeVector(const RegType* regs, int insn_reg_count,
+ uint8_t* data);
+
+ /*
+ * Double-check the map.
+ *
+ * We run through all of the data in the map, and compare it to the original.
+ * Only works on uncompressed data.
+ */
+ static bool VerifyMap(VerifierData* vdata, const RegisterMap* map);
+
+ /* Compare two register maps. Returns true if they're equal, false if not. */
+ static bool CompareMaps(const RegisterMap* map1, const RegisterMap* map2);
+
+ /* Compute the size, in bytes, of a register map. */
+ static size_t ComputeRegisterMapSize(const RegisterMap* map);
+
+ /*
+ * Compute the difference between two bit vectors.
+ *
+ * If "leb_out_buf" is non-NULL, we output the bit indices in ULEB128 format
+ * as we go. Otherwise, we just generate the various counts.
+ *
+ * The bit vectors are compared byte-by-byte, so any unused bits at the
+ * end must be zero.
+ *
+ * Returns the number of bytes required to hold the ULEB128 output.
+ *
+ * If "first_bit_changed_ptr" or "num_bits_changed_ptr" are non-NULL, they
+ * will receive the index of the first changed bit and the number of changed
+ * bits, respectively.
+ */
+ static int ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
+ int byte_width, int* first_bit_changed_ptr, int* num_bits_changed_ptr,
+ uint8_t* leb_out_buf);
+
+ /*
+ * Compress the register map with differential encoding.
+ *
+ * On success, returns a newly-allocated RegisterMap. If the map is not
+ * compatible for some reason, or fails to get smaller, this will return NULL.
+ */
+ static RegisterMap* CompressMapDifferential(const RegisterMap* map);
+
+ /*
+ * Expand a compressed map to an uncompressed form.
+ *
+ * Returns a newly-allocated RegisterMap on success, or NULL on failure.
+ *
+ * TODO: consider using the linear allocator or a custom allocator with
+ * LRU replacement for these instead of the native heap.
+ */
+ static RegisterMap* UncompressMapDifferential(const RegisterMap* map);
+
+
/* Verify a class. Returns "true" on success. */
static bool VerifyClass(Class* klass);
@@ -1543,95 +1669,6 @@
const Instruction::DecodedInstruction* dec_insn, MethodType method_type,
bool is_range, bool is_super, VerifyError* failure);
- /*
- * Generate the register map for a method that has just been verified
- * (i.e. we're doing this as part of verification).
- *
- * For type-precise determination we have all the data we need, so we
- * just need to encode it in some clever fashion.
- *
- * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
- */
- static RegisterMap* GenerateRegisterMapV(VerifierData* vdata);
-
- /*
- * Determine if the RegType value is a reference type.
- *
- * Ordinarily we include kRegTypeZero in the "is it a reference"
- * check. There's no value in doing so here, because we know
- * the register can't hold anything but zero.
- */
- static inline bool IsReferenceType(RegType type) {
- return (type > kRegTypeMAX || type == kRegTypeUninit);
- }
-
- /* Toggle the value of the "idx"th bit in "ptr". */
- static inline void ToggleBit(uint8_t* ptr, int idx) {
- ptr[idx >> 3] ^= 1 << (idx & 0x07);
- }
-
- /*
- * Given a line of registers, output a bit vector that indicates whether
- * or not the register holds a reference type (which could be null).
- *
- * We use '1' to indicate it's a reference, '0' for anything else (numeric
- * value, uninitialized data, merge conflict). Register 0 will be found
- * in the low bit of the first byte.
- */
- static void OutputTypeVector(const RegType* regs, int insn_reg_count,
- uint8_t* data);
-
- /*
- * Double-check the map.
- *
- * We run through all of the data in the map, and compare it to the original.
- * Only works on uncompressed data.
- */
- static bool VerifyMap(VerifierData* vdata, const RegisterMap* map);
-
- /* Compare two register maps. Returns true if they're equal, false if not. */
- static bool CompareMaps(const RegisterMap* map1, const RegisterMap* map2);
-
- /* Compute the size, in bytes, of a register map. */
- static size_t ComputeRegisterMapSize(const RegisterMap* map);
-
- /*
- * Compute the difference between two bit vectors.
- *
- * If "leb_out_buf" is non-NULL, we output the bit indices in ULEB128 format
- * as we go. Otherwise, we just generate the various counts.
- *
- * The bit vectors are compared byte-by-byte, so any unused bits at the
- * end must be zero.
- *
- * Returns the number of bytes required to hold the ULEB128 output.
- *
- * If "first_bit_changed_ptr" or "num_bits_changed_ptr" are non-NULL, they
- * will receive the index of the first changed bit and the number of changed
- * bits, respectively.
- */
- static int ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
- int byte_width, int* first_bit_changed_ptr, int* num_bits_changed_ptr,
- uint8_t* leb_out_buf);
-
- /*
- * Compress the register map with differential encoding.
- *
- * On success, returns a newly-allocated RegisterMap. If the map is not
- * compatible for some reason, or fails to get smaller, this will return NULL.
- */
- static RegisterMap* CompressMapDifferential(const RegisterMap* map);
-
- /*
- * Expand a compressed map to an uncompressed form.
- *
- * Returns a newly-allocated RegisterMap on success, or NULL on failure.
- *
- * TODO: consider using the linear allocator or a custom allocator with
- * LRU replacement for these instead of the native heap.
- */
- static RegisterMap* UncompressMapDifferential(const RegisterMap* map);
-
DISALLOW_COPY_AND_ASSIGN(DexVerifier);
};