NativePcOffsetToReferenceMap
Rather than translate a native PC to a Dex PC and then to the reference
bitmap, just go straight from the native PC to the reference bitmap.
Encode the native PC offsets using a hash rather than linearly
searching.
Change-Id: Iee1073d93c941c0a31f639e5f23cea9e9f747bee
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index dff30be..ca0a933 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include "gc_map.h"
+#include "verifier/dex_gc_map.h"
+#include "verifier/method_verifier.h"
+
namespace art {
void setMemRefType(LIR* lir, bool isLoad, int memType)
@@ -768,6 +772,114 @@
}
}
+class NativePcToReferenceMapBuilder {
+ public:
+ NativePcToReferenceMapBuilder(std::vector<uint8_t>* table,
+ size_t entries, uint32_t max_native_offset,
+ size_t references_width) : entries_(entries),
+ references_width_(references_width), in_use_(entries),
+ table_(table) {
+ // Compute width in bytes needed to hold max_native_offset.
+ native_offset_width_ = 0;
+ while (max_native_offset != 0) {
+ native_offset_width_++;
+ max_native_offset >>= 8;
+ }
+ // Resize table and set up header.
+ table->resize((EntryWidth() * entries) + sizeof(uint32_t));
+ CHECK_LT(native_offset_width_, 1U << 8);
+ (*table)[0] = native_offset_width_;
+ CHECK_LT(references_width_, 1U << 8);
+ (*table)[1] = references_width_;
+ CHECK_LT(entries, 1U << 16);
+ (*table)[2] = entries & 0xFF;
+ (*table)[3] = (entries >> 8) & 0xFF;
+ }
+
+ void AddEntry(uint32_t native_offset, const uint8_t* references) {
+ size_t table_index = TableIndex(native_offset);
+ while (in_use_[table_index]) {
+ table_index = (table_index + 1) % entries_;
+ }
+ in_use_[table_index] = true;
+ SetNativeOffset(table_index, native_offset);
+ DCHECK_EQ(native_offset, GetNativeOffset(table_index));
+ SetReferences(table_index, references);
+ }
+
+ private:
+ size_t TableIndex(uint32_t native_offset) {
+ return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_;
+ }
+
+ uint32_t GetNativeOffset(size_t table_index) {
+ uint32_t native_offset = 0;
+ size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t);
+ for (size_t i = 0; i < native_offset_width_; i++) {
+ native_offset |= (*table_)[table_offset + i] << (i * 8);
+ }
+ return native_offset;
+ }
+
+ void SetNativeOffset(size_t table_index, uint32_t native_offset) {
+ size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t);
+ for (size_t i = 0; i < native_offset_width_; i++) {
+ (*table_)[table_offset + i] = (native_offset >> (i * 8)) & 0xFF;
+ }
+ }
+
+ void SetReferences(size_t table_index, const uint8_t* references) {
+ size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t);
+ memcpy(&(*table_)[table_offset + native_offset_width_], references, references_width_);
+ }
+
+ size_t EntryWidth() const {
+ return native_offset_width_ + references_width_;
+ }
+
+ // Number of entries in the table.
+ const size_t entries_;
+ // Number of bytes used to encode the reference bitmap.
+ const size_t references_width_;
+ // Number of bytes used to encode a native offset.
+ size_t native_offset_width_;
+ // Entries that are in use.
+ std::vector<bool> in_use_;
+ // The table we're building.
+ std::vector<uint8_t>* const table_;
+};
+
+static void createNativeGcMap(CompilationUnit* cUnit) {
+ const std::vector<uint32_t>& mapping_table = cUnit->mappingTable;
+ uint32_t max_native_offset = 0;
+ for (size_t i = 0; i < mapping_table.size(); i += 2) {
+ uint32_t native_offset = mapping_table[i + 0];
+ if (native_offset > max_native_offset) {
+ max_native_offset = native_offset;
+ }
+ }
+ Compiler::MethodReference method_ref(cUnit->dex_file, cUnit->method_idx);
+ const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref);
+ verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4);
+ // Compute native offset to references size.
+ NativePcToReferenceMapBuilder native_gc_map_builder(&cUnit->nativeGcMap,
+ mapping_table.size() / 2, max_native_offset,
+ dex_gc_map.RegWidth());
+
+ for (size_t i = 0; i < mapping_table.size(); i += 2) {
+ uint32_t native_offset = mapping_table[i + 0];
+ uint32_t dex_pc = mapping_table[i + 1];
+ const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
+ if (references != NULL) {
+ native_gc_map_builder.AddEntry(native_offset, references);
+ } else {
+ // TODO: there is a mapping table entry but no reference bitmap. This happens because of
+ // catch block entries. We should check that the dex_pc corresponds with a catch block
+ // here.
+ }
+ }
+}
+
/* Determine the offset of each literal field */
int assignLiteralOffset(CompilationUnit* cUnit, int offset)
{
@@ -874,10 +986,10 @@
// Install fill array data
installFillArrayData(cUnit);
- /*
- * Create the mapping table
- */
+ // Create the mapping table and native offset to reference map.
createMappingTable(cUnit);
+
+ createNativeGcMap(cUnit);
}
/*