Handle de-duped CodeItems in dexlayout

De-duplicated (shared) CodeItems were added to the layout structures
multiple times, resulting in multiple update of offsets and
uninitialized data in the resulting dex files.

Bug: 67024225
Test: make test-art-host
Change-Id: I76ffd2cb52fe72eab3fb0dbf6ad8607951cee595
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 6b0b0f8..ffd1136 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1794,6 +1794,10 @@
     }
   }
 
+  // Removing duplicate CodeItems may expose other issues with downstream
+  // optimizations such as quickening.  But we need to ensure at least the weak
+  // forms of it currently in use do not break layout optimizations.
+  std::map<dex_ir::CodeItem*, uint32_t> original_code_item_offset;
   // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
   int32_t total_diff = 0;
   // The relative placement has no effect on correctness; it is used to ensure
@@ -1812,11 +1816,22 @@
           dex_ir::CodeItem* code_item = method->GetCodeItem();
           if (code_item != nullptr &&
               code_items_set.find(code_item) != code_items_set.end()) {
-            diff += UnsignedLeb128Size(code_item_offset)
-                - UnsignedLeb128Size(code_item->GetOffset());
-            code_item->SetOffset(code_item_offset);
-            code_item_offset +=
-                RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
+            // Compute where the CodeItem was originally laid out.
+            uint32_t original_offset = code_item->GetOffset();
+            auto it = original_code_item_offset.find(code_item);
+            if (it != original_code_item_offset.end()) {
+              original_offset = it->second;
+            } else {
+              original_code_item_offset[code_item] = code_item->GetOffset();
+              // Assign the new offset and move the pointer to allocate space.
+              code_item->SetOffset(code_item_offset);
+              code_item_offset +=
+                  RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
+            }
+            // Update the size of the encoded methods to reflect that the offset difference
+            // may have changed the ULEB128 length.
+            diff +=
+                UnsignedLeb128Size(code_item->GetOffset()) - UnsignedLeb128Size(original_offset);
           }
         }
       }