Snap for 11698527 from 4d45b8613f650acb36df41a6e970a9694ae464a2 to mainline-appsearch-release

Change-Id: Iddb7532ccd29c651d2d6dcec4618bc9a6ac65ecb
diff --git a/Android.mk b/Android.mk
index d560276..5c7f19d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -531,7 +531,9 @@
   lib64/libicuuc.so \
 
 PRIVATE_STATSD_APEX_DEPENDENCY_LIBS := \
+  lib/libstatspull.so \
   lib/libstatssocket.so \
+  lib64/libstatspull.so \
   lib64/libstatssocket.so \
 
 # Extracts files from an APEX into a location. The APEX can be either a .apex
diff --git a/artd/art_standalone_artd_tests.xml b/artd/art_standalone_artd_tests.xml
index 8a48b84..468b200 100644
--- a/artd/art_standalone_artd_tests.xml
+++ b/artd/art_standalone_artd_tests.xml
@@ -43,7 +43,6 @@
         <option name="mainline-module-package-name" value="com.android.art" />
     </object>
 
-    <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. -->
-    <!-- TODO(jiakaiz): Change this to U once `ro.build.version.sdk` is bumped. -->
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
+    <!-- Only run tests if the device under test is SDK version 34 (Android 14) or above. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk34ModuleController" />
 </configuration>
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index d5349b6..bf8f461 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -326,6 +326,11 @@
 apex_defaults {
     name: "com.android.art-devel-defaults",
     defaults: ["com.android.art-device-defaults"],
+    // Use a different manifest for the Debug & Testing ART APEXes (which have
+    // no prebuilts and are thus always built from sources), with a high version
+    // number that ensures that these packages can be installed on virtually all
+    // Android dessert releases.
+    manifest: "manifest-art-debug.json",
     native_shared_libs: art_runtime_base_native_device_only_debug_shared_libs +
         art_runtime_run_test_libs +
         art_runtime_debug_native_shared_libs +
@@ -630,3 +635,53 @@
     src: "linker.config.json",
     installable: false,
 }
+
+// sdk module types have 3 (maybe 4 for windows?) variants: linux, android, and common_os.
+// common_os depends on the linux/android variants and packages their artifacts into a zip file.
+// We want access to that zip file in art_release_zip, so we need to depend on only the common_os
+// variant of art-module-host-exports, which is what sdk_genrule does. Since sdk_genrule only has
+// 1 variant, we can then depend on it from a different type of genrule like regular genrule.
+sdk_genrule {
+    name: "art-module-host-exports-for-genrule",
+    defaults: ["art_module_source_build_genrule_defaults"],
+    srcs: [":art-module-host-exports"],
+    out: ["art-module-host-exports-current.zip"],
+    cmd: "cp $(in) $(out)",
+}
+
+// A zip containing ART binaries and ART bootclasspath jars.
+// At the time of writing, this is only for Compiler Explorer (https://godbolt.org).
+genrule {
+    name: "art_release_zip",
+    defaults: ["art_module_source_build_genrule_defaults"],
+    srcs: [
+        ":art-module-host-exports-for-genrule",
+        ":com.android.art",
+    ],
+    out: [
+        "art_release.zip",
+    ],
+    tools: [
+        "deapexer",
+        "debugfs",
+        "fsck.erofs",
+        "merge_zips",
+        "soong_zip",
+    ],
+    cmd: "$(location deapexer) " +
+        "--debugfs_path $(location debugfs) " +
+        "--fsckerofs_path $(location fsck.erofs) " +
+        "extract $(location :com.android.art) $(genDir)/extracted && " +
+
+        "$(location soong_zip) -o $(out).tmp -P bootjars -j " +
+        "-f $(genDir)/extracted/javalib/core-oj.jar " +
+        "-f $(genDir)/extracted/javalib/core-libart.jar " +
+        "-f $(genDir)/extracted/javalib/okhttp.jar " +
+        "-f $(genDir)/extracted/javalib/bouncycastle.jar " +
+        "-f $(genDir)/extracted/javalib/apache-xml.jar && " +
+
+        "$(location merge_zips) $(out) $(out).tmp $(location :art-module-host-exports-for-genrule)",
+    dist: {
+        targets: ["droidcore"],
+    },
+}
diff --git a/build/apex/manifest-art-debug.json b/build/apex/manifest-art-debug.json
new file mode 100644
index 0000000..5eee90c
--- /dev/null
+++ b/build/apex/manifest-art-debug.json
@@ -0,0 +1,17 @@
+{
+  // LINT.IfChange
+  "name": "com.android.art",
+
+  // High version number that ensures that packages using this manifest (Debug
+  // ART APEX, Testing ART APEX) can be installed on virtually all Android
+  // dessert releases.
+  "version": 990091000,
+
+  "provideNativeLibs": [
+    "libjdwp.so"
+  ],
+  "requireNativeLibs": [
+    "libicu_jni.so"
+  ]
+  // LINT.ThenChange(manifest-art.json)
+}
diff --git a/build/apex/manifest-art.json b/build/apex/manifest-art.json
index 4f20be6..83e2950 100644
--- a/build/apex/manifest-art.json
+++ b/build/apex/manifest-art.json
@@ -1,4 +1,5 @@
 {
+  // LINT.IfChange
   "name": "com.android.art",
 
   // Placeholder module version to be replaced during build.
@@ -11,4 +12,5 @@
   "requireNativeLibs": [
     "libicu_jni.so"
   ]
+  // LINT.ThenChange(manifest-art-debug.json)
 }
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index fee9091..f50fcf3 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1364,8 +1364,7 @@
                                                         method_reference,
                                                         resolved_method,
                                                         resolved_method_reference,
-                                                        proto_idx,
-                                                        !graph_->IsDebuggable());
+                                                        proto_idx);
   if (!HandleInvoke(invoke, operands, shorty, /* is_unresolved= */ false)) {
     return false;
   }
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index d2dbaa3..6307f92 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -700,7 +700,8 @@
                          bool is_volatile,
                          CodeGeneratorARM64* codegen) {
   LocationSummary* locations = invoke->GetLocations();
-  DCHECK((type == DataType::Type::kInt32) ||
+  DCHECK((type == DataType::Type::kInt8) ||
+         (type == DataType::Type::kInt32) ||
          (type == DataType::Type::kInt64) ||
          (type == DataType::Type::kReference));
   Location base_loc = locations->InAt(1);
@@ -791,6 +792,9 @@
 void IntrinsicLocationsBuilderARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
+void IntrinsicLocationsBuilderARM64::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGet(HInvoke* invoke) {
   CreateIntIntIntToIntLocations(allocator_, invoke);
@@ -819,6 +823,9 @@
 void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetObjectAcquire(HInvoke* invoke) {
   CreateIntIntIntToIntLocations(allocator_, invoke);
 }
+void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(allocator_, invoke);
+}
 
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGet(HInvoke* invoke) {
   VisitJdkUnsafeGet(invoke);
@@ -838,6 +845,9 @@
 void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
+void IntrinsicCodeGeneratorARM64::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGet(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
@@ -866,6 +876,9 @@
 void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetObjectAcquire(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
 }
+void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  GenUnsafeGet(invoke, DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
+}
 
 static void CreateIntIntIntIntToVoid(ArenaAllocator* allocator, HInvoke* invoke) {
   LocationSummary* locations =
@@ -903,6 +916,9 @@
 void IntrinsicLocationsBuilderARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicLocationsBuilderARM64::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
 
 void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePut(HInvoke* invoke) {
   CreateIntIntIntIntToVoid(allocator_, invoke);
@@ -940,6 +956,9 @@
 void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
   CreateIntIntIntIntToVoid(allocator_, invoke);
 }
+void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  CreateIntIntIntIntToVoid(allocator_, invoke);
+}
 
 static void GenUnsafePut(HInvoke* invoke,
                          DataType::Type type,
@@ -1008,6 +1027,9 @@
 void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicCodeGeneratorARM64::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
 
 void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke,
@@ -1093,6 +1115,13 @@
                /*is_ordered=*/ false,
                codegen_);
 }
+void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  GenUnsafePut(invoke,
+               DataType::Type::kInt8,
+               /*is_volatile=*/ false,
+               /*is_ordered=*/ false,
+               codegen_);
+}
 
 static void CreateUnsafeCASLocations(ArenaAllocator* allocator, HInvoke* invoke) {
   const bool can_call = gUseReadBarrier && IsUnsafeCASObject(invoke);
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 266b5bc..22c51c6 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -2902,6 +2902,14 @@
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
 
+void IntrinsicLocationsBuilderARMVIXL::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
+
 void IntrinsicLocationsBuilderARMVIXL::VisitJdkUnsafeGet(HInvoke* invoke) {
   CreateUnsafeGetLocations(invoke, codegen_, DataType::Type::kInt32, /*atomic=*/ false);
 }
@@ -2983,6 +2991,15 @@
       invoke, codegen_, DataType::Type::kReference, std::memory_order_acquire, /*atomic=*/ true);
 }
 
+void IntrinsicLocationsBuilderARMVIXL::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  CreateUnsafeGetLocations(invoke, codegen_, DataType::Type::kInt8, /*atomic=*/ false);
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  GenUnsafeGet(
+      invoke, codegen_, DataType::Type::kInt8, std::memory_order_relaxed, /*atomic=*/ false);
+}
+
 static void GenerateIntrinsicSet(CodeGeneratorARMVIXL* codegen,
                                  DataType::Type type,
                                  std::memory_order order,
@@ -3203,6 +3220,14 @@
   VisitJdkUnsafePutLongVolatile(invoke);
 }
 
+void IntrinsicLocationsBuilderARMVIXL::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
+
 void IntrinsicLocationsBuilderARMVIXL::VisitJdkUnsafePut(HInvoke* invoke) {
   CreateUnsafePutLocations(invoke, codegen_, DataType::Type::kInt32, /*atomic=*/ false);
 }
@@ -3215,6 +3240,18 @@
                codegen_);
 }
 
+void IntrinsicLocationsBuilderARMVIXL::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  CreateUnsafePutLocations(invoke, codegen_, DataType::Type::kInt8, /*atomic=*/ false);
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  GenUnsafePut(invoke,
+               DataType::Type::kInt8,
+               std::memory_order_relaxed,
+               /*atomic=*/ false,
+               codegen_);
+}
+
 void IntrinsicLocationsBuilderARMVIXL::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
   CreateUnsafePutLocations(invoke, codegen_, DataType::Type::kInt32, /*atomic=*/ true);
 }
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index d207220..345e9c6 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1691,6 +1691,12 @@
   Location output_loc = locations->Out();
 
   switch (type) {
+    case DataType::Type::kInt8: {
+      Register output = output_loc.AsRegister<Register>();
+      __ movsxb(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
+      break;
+    }
+
     case DataType::Type::kInt32: {
       Register output = output_loc.AsRegister<Register>();
       __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
@@ -1802,7 +1808,9 @@
 void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
-
+void IntrinsicLocationsBuilderX86::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
   VisitJdkUnsafeGet(invoke);
@@ -1822,7 +1830,9 @@
 void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
-
+void IntrinsicCodeGeneratorX86::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGet(HInvoke* invoke) {
   CreateIntIntIntToIntLocations(
@@ -1856,6 +1866,10 @@
   CreateIntIntIntToIntLocations(
       allocator_, invoke, DataType::Type::kReference, /*is_volatile=*/ true);
 }
+void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(
+      allocator_, invoke, DataType::Type::kInt8, /*is_volatile=*/ false);
+}
 
 void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGet(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
@@ -1884,6 +1898,9 @@
 void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetObjectAcquire(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
 }
+void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  GenUnsafeGet(invoke, DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
+}
 
 static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* allocator,
                                                        DataType::Type type,
@@ -1933,6 +1950,9 @@
 void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicLocationsBuilderX86::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
 
 void IntrinsicLocationsBuilderX86::VisitJdkUnsafePut(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(
@@ -1982,6 +2002,10 @@
   CreateIntIntIntIntToVoidPlusTempsLocations(
       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ true);
 }
+void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(
+      allocator_, DataType::Type::kInt8, invoke, /*is_volatile=*/ false);
+}
 
 // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
 // memory model.
@@ -2058,6 +2082,9 @@
 void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicCodeGeneratorX86::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
 
 void IntrinsicCodeGeneratorX86::VisitJdkUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
@@ -2099,6 +2126,9 @@
 void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
 }
+void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
+}
 
 static void CreateIntIntIntIntIntToInt(ArenaAllocator* allocator,
                                        DataType::Type type,
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 9d0d5f1..56bf5ea 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1883,6 +1883,10 @@
   CpuRegister output = output_loc.AsRegister<CpuRegister>();
 
   switch (type) {
+    case DataType::Type::kInt8:
+      __ movsxb(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
+      break;
+
     case DataType::Type::kInt32:
       __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
       break;
@@ -1965,6 +1969,9 @@
 void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
+void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafeGet(HInvoke* invoke) {
   CreateIntIntIntToIntLocations(allocator_, invoke);
@@ -1993,7 +2000,9 @@
 void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafeGetObjectAcquire(HInvoke* invoke) {
   CreateIntIntIntToIntLocations(allocator_, invoke);
 }
-
+void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(allocator_, invoke);
+}
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGet(HInvoke* invoke) {
   VisitJdkUnsafeGet(invoke);
@@ -2013,6 +2022,9 @@
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   VisitJdkUnsafeGetObjectVolatile(invoke);
 }
+void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetByte(HInvoke* invoke) {
+  VisitJdkUnsafeGetByte(invoke);
+}
 
 void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafeGet(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
@@ -2041,7 +2053,9 @@
 void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafeGetObjectAcquire(HInvoke* invoke) {
   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
 }
-
+void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
+  GenUnsafeGet(invoke, DataType::Type::kInt8, /*is_volatile=*/false, codegen_);
+}
 
 static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* allocator,
                                                        DataType::Type type,
@@ -2086,6 +2100,9 @@
 void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePut(invoke);
+}
 
 void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafePut(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(allocator_, DataType::Type::kInt32, invoke);
@@ -2123,6 +2140,9 @@
 void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
   CreateIntIntIntIntToVoidPlusTempsLocations(allocator_, DataType::Type::kInt64, invoke);
 }
+void IntrinsicLocationsBuilderX86_64::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(allocator_, DataType::Type::kUint8, invoke);
+}
 
 // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
 // memory model.
@@ -2185,6 +2205,9 @@
 void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   VisitJdkUnsafePutLongVolatile(invoke);
 }
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutByte(HInvoke* invoke) {
+  VisitJdkUnsafePutByte(invoke);
+}
 
 void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafePut(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
@@ -2226,6 +2249,9 @@
 void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
 }
+void IntrinsicCodeGeneratorX86_64::VisitJdkUnsafePutByte(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt8, /*is_volatile=*/false, codegen_);
+}
 
 static void CreateUnsafeCASLocations(ArenaAllocator* allocator,
                                      DataType::Type type,
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 28112d1..e0ff10c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4859,8 +4859,7 @@
                      // to pass intrinsic information to the HInvokePolymorphic node.
                      ArtMethod* resolved_method,
                      MethodReference resolved_method_reference,
-                     dex::ProtoIndex proto_idx,
-                     bool enable_intrinsic_opt)
+                     dex::ProtoIndex proto_idx)
       : HInvoke(kInvokePolymorphic,
                 allocator,
                 number_of_arguments,
@@ -4871,9 +4870,8 @@
                 resolved_method,
                 resolved_method_reference,
                 kPolymorphic,
-                enable_intrinsic_opt),
-        proto_idx_(proto_idx) {
-  }
+                /* enable_intrinsic_opt= */ true),
+        proto_idx_(proto_idx) {}
 
   bool IsClonable() const override { return true; }
 
diff --git a/dex2oat/art_standalone_dex2oat_cts_tests.xml b/dex2oat/art_standalone_dex2oat_cts_tests.xml
index a47febe..0a38fef 100644
--- a/dex2oat/art_standalone_dex2oat_cts_tests.xml
+++ b/dex2oat/art_standalone_dex2oat_cts_tests.xml
@@ -52,8 +52,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp/art_standalone_dex2oat_cts_tests" />
         <option name="module-name" value="art_standalone_dex2oat_cts_tests" />
-        <option name="ld-library-path-32" value="/apex/com.android.art/lib" />
-        <option name="ld-library-path-64" value="/apex/com.android.art/lib64" />
     </test>
 
     <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index df7835d..969b8c0 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -2792,7 +2792,7 @@
   const size_t java_alloc = heap->GetBytesAllocated();
   oss << "arena alloc=" << PrettySize(max_arena_alloc_) << " (" << max_arena_alloc_ << "B)";
   oss << " java alloc=" << PrettySize(java_alloc) << " (" << java_alloc << "B)";
-#if defined(__BIONIC__) || defined(__GLIBC__)
+#if defined(__BIONIC__) || defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
   const struct mallinfo info = mallinfo();
   const size_t allocated_space = static_cast<size_t>(info.uordblks);
   const size_t free_space = static_cast<size_t>(info.fordblks);
diff --git a/libartservice/service/java/com/android/server/art/ArtJni.java b/libartservice/service/java/com/android/server/art/ArtJni.java
index 2cc9ea8..f2868eb 100644
--- a/libartservice/service/java/com/android/server/art/ArtJni.java
+++ b/libartservice/service/java/com/android/server/art/ArtJni.java
@@ -56,8 +56,17 @@
         return validateClassLoaderContextNative(dexPath, classLoaderContext);
     }
 
+    /**
+     * Returns the name of the Garbage Collector currently in use in the Android Runtime.
+     */
+    @NonNull
+    public static String getGarbageCollector() {
+        return getGarbageCollectorNative();
+    }
+
     @Nullable private static native String validateDexPathNative(@NonNull String dexPath);
     @Nullable
     private static native String validateClassLoaderContextNative(
             @NonNull String dexPath, @NonNull String classLoaderContext);
+    @NonNull private static native String getGarbageCollectorNative();
 }
diff --git a/libartservice/service/java/com/android/server/art/Debouncer.java b/libartservice/service/java/com/android/server/art/Debouncer.java
index 61aea81..2aa7d0a 100644
--- a/libartservice/service/java/com/android/server/art/Debouncer.java
+++ b/libartservice/service/java/com/android/server/art/Debouncer.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -32,7 +34,8 @@
 public class Debouncer {
     @NonNull private Supplier<ScheduledExecutorService> mScheduledExecutorFactory;
     private final long mIntervalMs;
-    @Nullable private ScheduledFuture<?> mCurrentTask = null;
+    @GuardedBy("this") @Nullable private ScheduledFuture<?> mCurrentTask = null;
+    @GuardedBy("this") @Nullable private ScheduledExecutorService mExecutor = null;
 
     public Debouncer(
             long intervalMs, @NonNull Supplier<ScheduledExecutorService> scheduledExecutorFactory) {
@@ -40,6 +43,23 @@
         mIntervalMs = intervalMs;
     }
 
+    private void runTask(@NonNull Runnable command, @NonNull ScheduledExecutorService executor) {
+        synchronized (this) {
+            // In rare cases, at this point, another task may have been scheduled on the same
+            // executor, and `mExecutor` will be null or a new executor when that task is run, but
+            // that's okay. Either that task won't pass the check below or it will be cancelled.
+            // For simplicity, every task only shuts down its own executor.
+            // We only need to guarantee the following:
+            // - No new task is scheduled on an executor after the executor is shut down.
+            // - Every executor is eventually shut down.
+            if (mExecutor == executor) {
+                mExecutor.shutdown();
+                mExecutor = null;
+            }
+        }
+        command.run();
+    }
+
     /**
      * Runs the given command after the interval has passed. If another command comes in during
      * this interval, the previous one will never run.
@@ -48,8 +68,11 @@
         if (mCurrentTask != null) {
             mCurrentTask.cancel(false /* mayInterruptIfRunning */);
         }
-        ScheduledExecutorService executor = mScheduledExecutorFactory.get();
-        mCurrentTask = executor.schedule(command, mIntervalMs, TimeUnit.MILLISECONDS);
-        executor.shutdown();
+        if (mExecutor == null) {
+            mExecutor = mScheduledExecutorFactory.get();
+        }
+        ScheduledExecutorService executor = mExecutor;
+        mCurrentTask = mExecutor.schedule(
+                () -> runTask(command, executor), mIntervalMs, TimeUnit.MILLISECONDS);
     }
 }
diff --git a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
index c73f71b..b9d0afe 100644
--- a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
@@ -1173,7 +1173,7 @@
 
         @NonNull
         public ScheduledExecutorService createScheduledExecutor() {
-            return Executors.newSingleThreadScheduledExecutor();
+            return Executors.newScheduledThreadPool(1 /* corePoolSize */);
         }
 
         @NonNull
diff --git a/libartservice/service/java/com/android/server/art/DumpHelper.java b/libartservice/service/java/com/android/server/art/DumpHelper.java
index 2a640ec..70d7f8c 100644
--- a/libartservice/service/java/com/android/server/art/DumpHelper.java
+++ b/libartservice/service/java/com/android/server/art/DumpHelper.java
@@ -75,6 +75,7 @@
                 .stream()
                 .sorted(Comparator.comparing(PackageState::getPackageName))
                 .forEach(pkgState -> dumpPackage(pw, snapshot, pkgState));
+        pw.printf("\nCurrent GC: %s\n", ArtJni.getGarbageCollector());
     }
 
     /**
diff --git a/libartservice/service/java/com/android/server/art/ReasonMapping.java b/libartservice/service/java/com/android/server/art/ReasonMapping.java
index 7c64abf..2a1c81b 100644
--- a/libartservice/service/java/com/android/server/art/ReasonMapping.java
+++ b/libartservice/service/java/com/android/server/art/ReasonMapping.java
@@ -188,13 +188,14 @@
 
     /**
      * Loads the concurrency from the system property, for batch dexopt ({@link
-     * ArtManagerLocal#dexoptPackages}), or 1 if the system property is not found or cannot be
-     * parsed.
+     * ArtManagerLocal#dexoptPackages}). The default is tuned to strike a good balance between
+     * device load and dexopt coverage, depending on the situation.
      *
      * @hide
      */
     public static int getConcurrencyForReason(@NonNull @BatchDexoptReason String reason) {
         return SystemProperties.getInt("persist.device_config.runtime." + reason + "_concurrency",
-                SystemProperties.getInt("pm.dexopt." + reason + ".concurrency", 1 /* def */));
+                SystemProperties.getInt("pm.dexopt." + reason + ".concurrency",
+                        reason.equals(REASON_BG_DEXOPT) ? 4 : 1 /* def */));
     }
 }
diff --git a/libartservice/service/javatests/com/android/server/art/DebouncerTest.java b/libartservice/service/javatests/com/android/server/art/DebouncerTest.java
index bf0bc70..cf6eee4 100644
--- a/libartservice/service/javatests/com/android/server/art/DebouncerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DebouncerTest.java
@@ -61,5 +61,13 @@
         mMockClock.advanceTime(1000);
 
         assertThat(list).containsExactly(2, 5).inOrder();
+
+        // Verify that we don't create too many executors, and all the executors we create are
+        // eventually shut down.
+        List<MockClock.ScheduledExecutor> executors = mMockClock.getCreatedExecutors();
+        assertThat(executors).hasSize(2);
+        for (MockClock.ScheduledExecutor executor : executors) {
+            assertThat(executor.isShutdown()).isTrue();
+        }
     }
 }
diff --git a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java
index 3833249..5dbe213 100644
--- a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java
@@ -62,7 +62,7 @@
 
     @Rule
     public StaticMockitoRule mockitoRule =
-            new StaticMockitoRule(SystemProperties.class, Constants.class);
+            new StaticMockitoRule(SystemProperties.class, Constants.class, ArtJni.class);
 
     @Mock private DumpHelper.Injector mInjector;
     @Mock private ArtManagerLocal mArtManagerLocal;
@@ -83,6 +83,8 @@
                 .when(SystemProperties.get(argThat(arg -> arg.startsWith("ro.dalvik.vm.isa."))))
                 .thenReturn("");
 
+        lenient().when(ArtJni.getGarbageCollector()).thenReturn("CollectorTypeCMC");
+
         lenient().when(mInjector.getArtManagerLocal()).thenReturn(mArtManagerLocal);
         lenient().when(mInjector.getDexUseManager()).thenReturn(mDexUseManagerLocal);
         lenient().when(mInjector.getArtd()).thenReturn(mArtd);
@@ -132,7 +134,9 @@
                 + "    arm: [status=verify] [reason=install] [primary-abi]\n"
                 + "      [location is /data/app/bar/oat/arm/base.odex]\n"
                 + "    arm64: [status=verify] [reason=install]\n"
-                + "      [location is /data/app/bar/oat/arm64/base.odex]\n";
+                + "      [location is /data/app/bar/oat/arm64/base.odex]\n"
+                + "\n"
+                + "Current GC: CollectorTypeCMC\n";
 
         var stringWriter = new StringWriter();
         mDumpHelper.dump(new PrintWriter(stringWriter), mSnapshot);
diff --git a/libartservice/service/javatests/com/android/server/art/testing/MockClock.java b/libartservice/service/javatests/com/android/server/art/testing/MockClock.java
index 7b4b23b..fb77f09 100644
--- a/libartservice/service/javatests/com/android/server/art/testing/MockClock.java
+++ b/libartservice/service/javatests/com/android/server/art/testing/MockClock.java
@@ -50,6 +50,11 @@
         }
     }
 
+    @NonNull
+    public List<ScheduledExecutor> getCreatedExecutors() {
+        return mExecutors;
+    }
+
     public class ScheduledExecutor extends ScheduledThreadPoolExecutor {
         // The second element of the pair is the scheduled time.
         @NonNull
diff --git a/libartservice/service/native/service.cc b/libartservice/service/native/service.cc
index 7d223e5..5901efd 100644
--- a/libartservice/service/native/service.cc
+++ b/libartservice/service/native/service.cc
@@ -24,7 +24,9 @@
 #include "android-base/file.h"
 #include "android-base/result.h"
 #include "class_loader_context.h"
+#include "gc/heap.h"
 #include "nativehelper/utils.h"
+#include "runtime.h"
 
 namespace art {
 namespace service {
@@ -76,6 +78,10 @@
   return {};
 }
 
+std::string GetGarbageCollector() {
+  return Runtime::Current()->GetHeap()->GetForegroundCollectorName();
+}
+
 extern "C" JNIEXPORT jstring JNICALL
 Java_com_android_server_art_ArtJni_validateDexPathNative(JNIEnv* env, jobject, jstring j_dex_path) {
   std::string dex_path(GET_UTF_OR_RETURN(env, j_dex_path));
@@ -116,5 +122,10 @@
   return nullptr;
 }
 
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_android_server_art_ArtJni_getGarbageCollectorNative(JNIEnv* env, jobject) {
+  return CREATE_UTF_OR_RETURN(env, GetGarbageCollector()).release();
+}
+
 }  // namespace service
 }  // namespace art
diff --git a/libartservice/service/native/service.h b/libartservice/service/native/service.h
index 7f43f17..85c7dcd 100644
--- a/libartservice/service/native/service.h
+++ b/libartservice/service/native/service.h
@@ -34,6 +34,8 @@
 
 android::base::Result<void> ValidateDexPath(const std::string& dex_path);
 
+std::string GetGarbageCollector();
+
 }  // namespace service
 }  // namespace art
 
diff --git a/libartservice/service/native/service_test.cc b/libartservice/service/native/service_test.cc
index 8300bf5..d1d429e 100644
--- a/libartservice/service/native/service_test.cc
+++ b/libartservice/service/native/service_test.cc
@@ -17,6 +17,7 @@
 #include "service.h"
 
 #include "android-base/result-gmock.h"
+#include "common_runtime_test.h"
 #include "gtest/gtest.h"
 
 namespace art {
@@ -106,6 +107,12 @@
               HasError(WithMessage("Path '/a/\0/b.apk' has invalid character '\\0'"s)));
 }
 
+class ArtServiceGcTest : public CommonRuntimeTest {};
+
+TEST_F(ArtServiceGcTest, GetGarbageCollector) {
+  EXPECT_THAT(GetGarbageCollector(), testing::HasSubstr("CollectorType"));
+}
+
 }  // namespace
 }  // namespace service
 }  // namespace art
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index d9c5211..cc2f641 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -319,7 +319,14 @@
         // Emit what was previously there, if anything
         if (local_in_reg[reg].is_live_) {
           local_in_reg[reg].end_address_ = address;
-          new_local_callback(local_in_reg[reg]);
+          // Parameters with generic types cannot be encoded in the debug_info_item header. So d8
+          // encodes it as null in the header with start and end address as 0. There will be a
+          // START_LOCAL_EXTENDED that will declare the parameter with correct signature
+          // Debuggers get confused when they see empty ranges. So don't emit them.
+          // See b/297843934 for more details.
+          if (local_in_reg[reg].end_address_ != 0) {
+            new_local_callback(local_in_reg[reg]);
+          }
         }
 
         local_in_reg[reg].name_ = index_to_string_data(name_idx);
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index b2d29f1..dc6965f 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -82,14 +82,13 @@
     defaults: ["libnativebridge-test-case-defaults"],
 }
 
-cc_defaults {
-    name: "libnativebridge-tests-defaults",
+cc_test {
+    name: "libnativebridge-tests",
     defaults: [
         "art_defaults",
         "art_test_defaults",
     ],
-    // TODO(mast): Split up art_gtest_defaults so that it can be used for the
-    // following without pulling in lots of libs.
+
     target: {
         linux: {
             cflags: [
@@ -100,11 +99,6 @@
             ],
         },
     },
-}
-
-cc_test {
-    name: "libnativebridge-tests",
-    defaults: ["libnativebridge-tests-defaults"],
 
     // native_bridge.cc doesn't support reloading the native bridge after
     // unloading, so each test needs to be its own process.
@@ -154,35 +148,14 @@
     header_libs: ["libbase_headers"],
 }
 
-// Variant of libnativebridge-tests that is part of CTS to verify backed-by API
-// coverage.
+// Very basic tests in CTS to verify backed-by API coverage of the exported API
+// in libnativebridge.map.txt.
 cc_test {
     name: "art_libnativebridge_cts_tests",
-    defaults: [
-        "art_standalone_test_defaults",
-        "libnativebridge-tests-defaults",
-    ],
-
-    // TODO(b/189484095): Pick only a subset of the tests in
-    // libnativebridge-tests that don't require the native bridge lib to be
-    // loaded, to avoid the problems with test_per_src and pushing the extra
-    // libnativebridge*-test-case.so files to device through tradefed.
-    srcs: [
-        // ValidNameNativeBridge_test.cpp needs to be first due to global state
-        // had_error that isn't reset between tests.
-        "ValidNameNativeBridge_test.cpp",
-        "NeedsNativeBridge_test.cpp",
-        "UnavailableNativeBridge_test.cpp",
-    ],
-    static_libs: [
-        "libdl_android",
-        "libnativebridge",
-    ],
-    shared_libs: [
-        "liblog",
-    ],
-    header_libs: ["libbase_headers"],
-
+    defaults: ["art_standalone_test_defaults"],
+    shared_libs: ["libnativebridge"],
+    static_libs: ["libbase"],
+    srcs: ["libnativebridge_api_test.cpp"],
     test_config_template: ":art-gtests-target-standalone-cts-template",
     test_suites: [
         "cts",
@@ -194,12 +167,10 @@
 
 cc_test {
     name: "libnativebridge-lazy-tests",
-    defaults: ["libnativebridge-tests-defaults"],
-    host_supported: false,
-    test_suites: ["device-tests"],
+    defaults: ["art_standalone_test_defaults"],
     static_libs: [
         "libbase",
         "libnativebridge_lazy",
     ],
-    srcs: ["libnativebridge_lazy_test.cpp"],
+    srcs: ["libnativebridge_api_test.cpp"],
 }
diff --git a/libnativebridge/tests/libnativebridge_lazy_test.cpp b/libnativebridge/tests/libnativebridge_api_test.cpp
similarity index 74%
rename from libnativebridge/tests/libnativebridge_lazy_test.cpp
rename to libnativebridge/tests/libnativebridge_api_test.cpp
index e1d66f5..037587c 100644
--- a/libnativebridge/tests/libnativebridge_lazy_test.cpp
+++ b/libnativebridge/tests/libnativebridge_api_test.cpp
@@ -21,33 +21,34 @@
 
 namespace android {
 
-class NativeBridgeLazyTest : public ::testing::Test {};
+class NativeBridgeApiTest : public ::testing::Test {};
 
+// Test the exported API in libnativebridge and libnativebridge_lazy.
 // The testing we can do here is limited since there's no exported API to
 // actually load the native bridge, but we only need to test the trivial
 // wrappers.
 
-TEST_F(NativeBridgeLazyTest, NeedsNativeBridge) {
+TEST_F(NativeBridgeApiTest, NeedsNativeBridge) {
   EXPECT_FALSE(NeedsNativeBridge(ABI_STRING));
 }
 
-TEST_F(NativeBridgeLazyTest, PreInitializeNativeBridge) {
+TEST_F(NativeBridgeApiTest, PreInitializeNativeBridge) {
   EXPECT_FALSE(PreInitializeNativeBridge(nullptr, ""));
 }
 
-TEST_F(NativeBridgeLazyTest, NativeBridgeAvailable) {
+TEST_F(NativeBridgeApiTest, NativeBridgeAvailable) {
   EXPECT_FALSE(NativeBridgeAvailable());
 }
 
-TEST_F(NativeBridgeLazyTest, NativeBridgeInitialized) {
+TEST_F(NativeBridgeApiTest, NativeBridgeInitialized) {
   EXPECT_FALSE(NativeBridgeInitialized());
 }
 
-TEST_F(NativeBridgeLazyTest, NativeBridgeGetTrampoline) {
+TEST_F(NativeBridgeApiTest, NativeBridgeGetTrampoline) {
   EXPECT_EQ(nullptr, NativeBridgeGetTrampoline(nullptr, nullptr, nullptr, 0));
 }
 
-TEST_F(NativeBridgeLazyTest, NativeBridgeGetError) {
+TEST_F(NativeBridgeApiTest, NativeBridgeGetError) {
   EXPECT_STREQ("native bridge is not initialized", NativeBridgeGetError());
 }
 
diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index 809e18d..071d8ba 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -168,7 +168,10 @@
                 "odr_metrics_record.cc",
                 "odr_statslog_android.cc",
             ],
-            shared_libs: ["libstatssocket"],
+            shared_libs: [
+                "libstatspull",
+                "libstatssocket",
+            ],
         },
         host: {
             srcs: ["odr_statslog_host.cc"],
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 1c4b871..2f655b1 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -444,7 +444,8 @@
             ],
             shared_libs: [
                 "libdl_android",
-                "libstatssocket",
+                "libstatspull", // for pulled atoms
+                "libstatssocket", // for pulled atoms
                 "libz", // For adler32.
                 "heapprofd_client_api",
             ],
@@ -1061,6 +1062,7 @@
     export_generated_headers: ["statslog_art.h"],
     shared_libs: [
         "liblog",
+        "libstatspull",
         "libstatssocket",
         "libutils",
     ],
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4e18987..a5a9e9c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2234,7 +2234,10 @@
     // boot image method optimization. We need to disable it before doing
     // ResetCounter below, as counters of shared memory method always hold the
     // "hot" value.
-    if (runtime->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath()) {
+    // For debuggable runtimes we don't use AOT code, so don't use shared memory
+    // optimization so the methods can be JITed better.
+    if (runtime->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath() ||
+        runtime->IsJavaDebuggable()) {
       header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) {
         method.ClearMemorySharedMethod();
       }, space->Begin(), image_pointer_size_);
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 652368c..6f1452e 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -43,12 +43,16 @@
 // Static fault manger object accessed by signal handler.
 FaultManager fault_manager;
 
-// This needs to be NO_INLINE since some debuggers do not read the inline-info to set a breakpoint
-// if it isn't.
+// These need to be NO_INLINE since some debuggers do not read the inline-info to set a breakpoint
+// if they aren't.
 extern "C" NO_INLINE __attribute__((visibility("default"))) void art_sigsegv_fault() {
   // Set a breakpoint here to be informed when a SIGSEGV is unhandled by ART.
   VLOG(signals)<< "Caught unknown SIGSEGV in ART fault handler - chaining to next handler.";
 }
+extern "C" NO_INLINE __attribute__((visibility("default"))) void art_sigbus_fault() {
+  // Set a breakpoint here to be informed when a SIGBUS is unhandled by ART.
+  VLOG(signals) << "Caught unknown SIGBUS in ART fault handler - chaining to next handler.";
+}
 
 // Signal handler called on SIGSEGV.
 static bool art_sigsegv_handler(int sig, siginfo_t* info, void* context) {
@@ -233,7 +237,13 @@
   // Simulate a crash in a handler.
   raise(SIGBUS);
 #endif
-  return Runtime::Current()->GetHeap()->MarkCompactCollector()->SigbusHandler(info);
+  if (Runtime::Current()->GetHeap()->MarkCompactCollector()->SigbusHandler(info)) {
+    return true;
+  }
+
+  // Set a breakpoint in this function to catch unhandled signals.
+  art_sigbus_fault();
+  return false;
 }
 
 inline void FaultManager::CheckForUnrecognizedImplicitSuspendCheckInBootImage(
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 2d1d393..ab82f14 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -16,20 +16,18 @@
 
 #include "heap.h"
 
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <limits>
-#include "android-base/thread_annotations.h"
-#if defined(__BIONIC__) || defined(__GLIBC__)
-#include <malloc.h>  // For mallinfo()
-#endif
 #include <memory>
 #include <random>
-#include <unistd.h>
-#include <sys/types.h>
+#include <sstream>
 #include <vector>
 
-#include "android-base/stringprintf.h"
-
 #include "allocation_listener.h"
+#include "android-base/stringprintf.h"
+#include "android-base/thread_annotations.h"
 #include "art_field-inl.h"
 #include "backtrace_helper.h"
 #include "base/allocator.h"
@@ -108,6 +106,10 @@
 #include "verify_object-inl.h"
 #include "well_known_classes.h"
 
+#if defined(__BIONIC__) || defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
+#include <malloc.h>  // For mallinfo()
+#endif
+
 namespace art {
 
 #ifdef ART_TARGET_ANDROID
@@ -2655,7 +2657,7 @@
 
 size_t Heap::GetNativeBytes() {
   size_t malloc_bytes;
-#if defined(__BIONIC__) || defined(__GLIBC__)
+#if defined(__BIONIC__) || defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
   IF_GLIBC(size_t mmapped_bytes;)
   struct mallinfo mi = mallinfo();
   // In spite of the documentation, the jemalloc version of this call seems to do what we want,
@@ -4758,5 +4760,11 @@
   return true;
 }
 
+std::string Heap::GetForegroundCollectorName() {
+  std::ostringstream oss;
+  oss << foreground_collector_type_;
+  return oss.str();
+}
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d7f6948..489be37 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -843,6 +843,7 @@
   bool IsMovingGc() const { return IsMovingGc(CurrentCollectorType()); }
 
   CollectorType GetForegroundCollectorType() const { return foreground_collector_type_; }
+  std::string GetForegroundCollectorName();
 
   bool IsGcConcurrentAndMoving() const {
     if (IsGcConcurrent() && IsMovingGc(collector_type_)) {
diff --git a/runtime/gc/verification.h b/runtime/gc/verification.h
index 7a5d01a..a732556 100644
--- a/runtime/gc/verification.h
+++ b/runtime/gc/verification.h
@@ -40,7 +40,7 @@
  public:
   explicit Verification(gc::Heap* heap) : heap_(heap) {}
 
-  // Dump some reveant to debugging info about an object.
+  // Dump some debugging-relevant info about an object.
   std::string DumpObjectInfo(const void* obj, const char* tag) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 281c1f3..531448b 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -358,9 +358,11 @@
       case Intrinsics::kJdkUnsafeGet:
       case Intrinsics::kJdkUnsafeGetLong:
       case Intrinsics::kJdkUnsafeGetObject:
+      case Intrinsics::kJdkUnsafeGetByte:
       case Intrinsics::kJdkUnsafePutLong:
       case Intrinsics::kJdkUnsafePut:
       case Intrinsics::kJdkUnsafePutObject:
+      case Intrinsics::kJdkUnsafePutByte:
         return 0u;
       case Intrinsics::kFP16Ceil:
       case Intrinsics::kFP16Compare:
@@ -376,10 +378,12 @@
       case Intrinsics::kFP16Rint:
       case Intrinsics::kUnsafeGet:
       case Intrinsics::kUnsafeGetLong:
+      case Intrinsics::kUnsafeGetByte:
       case Intrinsics::kUnsafeGetObject:
       case Intrinsics::kUnsafePutLong:
       case Intrinsics::kUnsafePut:
       case Intrinsics::kUnsafePutObject:
+      case Intrinsics::kUnsafePutByte:
         return kAccCorePlatformApi;
       default:
         // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h
index 256cd2e..c4b687e 100644
--- a/runtime/intrinsics_list.h
+++ b/runtime/intrinsics_list.h
@@ -221,6 +221,7 @@
   V(UnsafeGetObjectVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;") \
   V(UnsafeGetLong, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLong", "(Ljava/lang/Object;J)J") \
   V(UnsafeGetLongVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLongVolatile", "(Ljava/lang/Object;J)J") \
+  V(UnsafeGetByte, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getByte", "(Ljava/lang/Object;J)B") \
   V(UnsafePut, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putInt", "(Ljava/lang/Object;JI)V") \
   V(UnsafePutOrdered, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedInt", "(Ljava/lang/Object;JI)V") \
   V(UnsafePutVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putIntVolatile", "(Ljava/lang/Object;JI)V") \
@@ -230,6 +231,7 @@
   V(UnsafePutLong, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLong", "(Ljava/lang/Object;JJ)V") \
   V(UnsafePutLongOrdered, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedLong", "(Ljava/lang/Object;JJ)V") \
   V(UnsafePutLongVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLongVolatile", "(Ljava/lang/Object;JJ)V") \
+  V(UnsafePutByte, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putByte", "(Ljava/lang/Object;JB)V") \
   V(UnsafeGetAndAddInt, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddInt", "(Ljava/lang/Object;JI)I") \
   V(UnsafeGetAndAddLong, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddLong", "(Ljava/lang/Object;JJ)J") \
   V(UnsafeGetAndSetInt, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetInt", "(Ljava/lang/Object;JI)I") \
@@ -253,6 +255,7 @@
   V(JdkUnsafeGetLong, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getLong", "(Ljava/lang/Object;J)J") \
   V(JdkUnsafeGetLongVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getLongVolatile", "(Ljava/lang/Object;J)J") \
   V(JdkUnsafeGetLongAcquire, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getLongAcquire", "(Ljava/lang/Object;J)J") \
+  V(JdkUnsafeGetByte, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getByte", "(Ljava/lang/Object;J)B") \
   V(JdkUnsafePut, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putInt", "(Ljava/lang/Object;JI)V") \
   V(JdkUnsafePutOrdered, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putOrderedInt", "(Ljava/lang/Object;JI)V") \
   V(JdkUnsafePutRelease, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putIntRelease", "(Ljava/lang/Object;JI)V") \
@@ -265,6 +268,7 @@
   V(JdkUnsafePutLongOrdered, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putOrderedLong", "(Ljava/lang/Object;JJ)V") \
   V(JdkUnsafePutLongVolatile, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putLongVolatile", "(Ljava/lang/Object;JJ)V") \
   V(JdkUnsafePutLongRelease, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putLongRelease", "(Ljava/lang/Object;JJ)V") \
+  V(JdkUnsafePutByte, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "putByte", "(Ljava/lang/Object;JB)V") \
   V(JdkUnsafeGetAndAddInt, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getAndAddInt", "(Ljava/lang/Object;JI)I") \
   V(JdkUnsafeGetAndAddLong, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getAndAddLong", "(Ljava/lang/Object;JJ)J") \
   V(JdkUnsafeGetAndSetInt, kVirtual, kNeedsEnvironment, kAllSideEffects, kCanThrow, "Ljdk/internal/misc/Unsafe;", "getAndSetInt", "(Ljava/lang/Object;JI)I") \
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 3472c78..b231cce 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -71,7 +71,7 @@
 static constexpr uint32_t kJitSlowStressDefaultOptimizeThreshold =
     kJitStressDefaultOptimizeThreshold / 2;
 
-static constexpr uint32_t kJitDefaultWarmupThreshold = 0x3fff;
+static constexpr uint32_t kJitDefaultWarmupThreshold = 0xffff;
 // Different warm-up threshold constants. These default to the equivalent warmup thresholds divided
 // by 2, but can be overridden at the command-line.
 static constexpr uint32_t kJitStressDefaultWarmupThreshold = kJitDefaultWarmupThreshold / 2;
diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc
index 2105bdb..6d96c6f 100644
--- a/runtime/metrics/statsd.cc
+++ b/runtime/metrics/statsd.cc
@@ -414,18 +414,30 @@
 
 std::unique_ptr<MetricsBackend> CreateStatsdBackend() { return std::make_unique<StatsdBackend>(); }
 
-void ReportDeviceMetrics() {
-  Runtime* runtime = Runtime::Current();
-  int32_t boot_image_status;
-  if (runtime->GetHeap()->HasBootImageSpace() && !runtime->HasImageWithProfile()) {
-    boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_FULL;
-  } else if (runtime->GetHeap()->HasBootImageSpace() &&
-             runtime->GetHeap()->GetBootImageSpaces()[0]->GetProfileFiles().empty()) {
-    boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_MINIMAL;
-  } else {
-    boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_NONE;
+AStatsManager_PullAtomCallbackReturn DeviceStatusCallback(int32_t atom_tag,
+                                                          AStatsEventList* data,
+                                                          [[maybe_unused]] void* cookie) {
+  if (atom_tag == statsd::ART_DEVICE_STATUS) {
+    Runtime* runtime = Runtime::Current();
+    int32_t boot_image_status;
+    if (runtime->GetHeap()->HasBootImageSpace() && !runtime->HasImageWithProfile()) {
+      boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_FULL;
+    } else if (runtime->GetHeap()->HasBootImageSpace() &&
+               runtime->GetHeap()->GetBootImageSpaces()[0]->GetProfileFiles().empty()) {
+      boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_MINIMAL;
+    } else {
+      boot_image_status = statsd::ART_DEVICE_DATUM_REPORTED__BOOT_IMAGE_STATUS__STATUS_NONE;
+    }
+    statsd::addAStatsEvent(data, atom_tag, boot_image_status);
+    return AStatsManager_PULL_SUCCESS;
   }
-  statsd::stats_write(statsd::ART_DEVICE_DATUM_REPORTED, boot_image_status);
+
+  return AStatsManager_PULL_SKIP;
+}
+
+void SetupCallbackForDeviceStatus() {
+  AStatsManager_setPullAtomCallback(
+      statsd::ART_DEVICE_STATUS, /*metadata=*/nullptr, DeviceStatusCallback, /*cookie=*/nullptr);
 }
 
 }  // namespace metrics
diff --git a/runtime/metrics/statsd.h b/runtime/metrics/statsd.h
index cb84825..77c0f1d 100644
--- a/runtime/metrics/statsd.h
+++ b/runtime/metrics/statsd.h
@@ -27,10 +27,10 @@
 // Statsd is only supported on Android
 #ifdef __ANDROID__
 std::unique_ptr<MetricsBackend> CreateStatsdBackend();
-void ReportDeviceMetrics();
+void SetupCallbackForDeviceStatus();
 #else
 inline std::unique_ptr<MetricsBackend> CreateStatsdBackend() { return nullptr; }
-inline void ReportDeviceMetrics() {}
+inline void SetupCallbackForDeviceStatus() {}
 #endif
 
 }  // namespace metrics
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 3fed8d4..ef2a137 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#include "monitor-inl.h"
+#include <android-base/properties.h>
 
 #include <vector>
 
 #include "android-base/stringprintf.h"
-
 #include "art_method-inl.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/mutex.h"
@@ -32,9 +31,11 @@
 #include "dex/dex_file_types.h"
 #include "dex/dex_instruction-inl.h"
 #include "entrypoints/entrypoint_utils-inl.h"
+#include "gc/verification-inl.h"
 #include "lock_word-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
+#include "monitor-inl.h"
 #include "object_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
@@ -42,7 +43,6 @@
 #include "thread_list.h"
 #include "verifier/method_verifier.h"
 #include "well_known_classes.h"
-#include <android-base/properties.h>
 
 static_assert(ART_USE_FUTEXES);
 
@@ -1522,18 +1522,29 @@
       // not be optimized out.
       success = stack_visitor->GetVReg(m, dex_reg, kReferenceVReg, &value);
       if (success) {
-        ObjPtr<mirror::Object> o = reinterpret_cast<mirror::Object*>(value);
-        callback(o, callback_context);
-        break;
+        mirror::Object* mp = reinterpret_cast<mirror::Object*>(value);
+        // TODO(b/299577730) Remove the extra checks here once the underlying bug is fixed.
+        const gc::Verification* v = Runtime::Current()->GetHeap()->GetVerification();
+        if (v->IsValidObject(mp)) {
+          ObjPtr<mirror::Object> o = mp;
+          callback(o, callback_context);
+          break;
+        } else {
+          LOG(ERROR) << "Encountered bad lock object: " << std::hex << value << std::dec;
+          success = false;
+        }
       }
     }
-    DCHECK(success) << "Failed to find/read reference for monitor-enter at dex pc "
-                    << dex_lock_info.dex_pc
-                    << " in method "
-                    << m->PrettyMethod();
     if (!success) {
-      LOG(WARNING) << "Had a lock reported for dex pc " << dex_lock_info.dex_pc
-                   << " but was not able to fetch a corresponding object!";
+      LOG(ERROR) << "Failed to find/read reference for monitor-enter at dex pc "
+                 << dex_lock_info.dex_pc << " in method " << m->PrettyMethod();
+      if (kIsDebugBuild) {
+        // Crash only in debug ART builds.
+        LOG(FATAL) << "Had a lock reported for a dex pc "
+                      "but was not able to fetch a corresponding object!";
+      } else {
+        LOG(ERROR) << "Held monitor information in stack trace will be incomplete!";
+      }
     }
   }
 }
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7eff246..e225d9e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1299,7 +1299,7 @@
     if (!odrefresh::UploadStatsIfAvailable(&err)) {
       LOG(WARNING) << "Failed to upload odrefresh metrics: " << err;
     }
-    metrics::ReportDeviceMetrics();
+    metrics::SetupCallbackForDeviceStatus();
   }
 
   if (LIKELY(automatically_set_jni_ids_indirection_) && CanSetJniIdType()) {
@@ -3333,10 +3333,12 @@
   return callbacks_.get();
 }
 
-// Used to patch boot image method entry point to interpreter bridge.
-class UpdateEntryPointsClassVisitor : public ClassVisitor {
+// Used to update boot image to not use AOT code. This is used when transitioning the runtime to
+// java debuggable. This visitor re-initializes the entry points without using AOT code. This also
+// disables shared hotness counters so the necessary methods can be JITed more efficiently.
+class DeoptimizeBootImageClassVisitor : public ClassVisitor {
  public:
-  explicit UpdateEntryPointsClassVisitor(instrumentation::Instrumentation* instrumentation)
+  explicit DeoptimizeBootImageClassVisitor(instrumentation::Instrumentation* instrumentation)
       : instrumentation_(instrumentation) {}
 
   bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES(Locks::mutator_lock_) {
@@ -3370,6 +3372,9 @@
         m.ClearPreCompiled();
         instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
       }
+
+      // Clear MemorySharedAccessFlags so the boot class methods can be JITed better.
+      m.ClearMemorySharedMethod();
     }
     return true;
   }
@@ -3390,7 +3395,7 @@
   // If we've already started and we are setting this runtime to debuggable,
   // we patch entry points of methods in boot image to interpreter bridge, as
   // boot image code may be AOT compiled as not debuggable.
-  UpdateEntryPointsClassVisitor visitor(GetInstrumentation());
+  DeoptimizeBootImageClassVisitor visitor(GetInstrumentation());
   GetClassLinker()->VisitClasses(&visitor);
   jit::Jit* jit = GetJit();
   if (jit != nullptr) {
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 81c86f1..20436d6 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -774,6 +774,15 @@
   CHECK_IMPLIES(trace_file == nullptr, output_mode == TraceOutputMode::kDDMS);
 
   uint16_t trace_version = GetTraceVersion(clock_source_);
+
+  // We initialize the start_time_ from the timestamp counter. This may not match
+  // with the monotonic timer but we only use this time to calculate the elapsed
+  // time from this point which should be the same for both cases.
+  // We record monotonic time at the start of the trace, because Android Studio
+  // fetches the monotonic timer from other places and matches these times to
+  // construct a cpu profile. See b/318052824 for more context.
+  uint64_t start_time_monotonic = start_time_ + (MicroTime() - GetMicroTime(GetTimestamp()));
+
   if (output_mode == TraceOutputMode::kStreaming) {
     trace_version |= 0xF0U;
   }
@@ -782,7 +791,7 @@
   Append4LE(buf_.get(), kTraceMagicValue);
   Append2LE(buf_.get() + 4, trace_version);
   Append2LE(buf_.get() + 6, kTraceHeaderLength);
-  Append8LE(buf_.get() + 8, start_time_);
+  Append8LE(buf_.get() + 8, start_time_monotonic);
   if (trace_version >= kTraceVersionDualClock) {
     uint16_t record_size = GetRecordSize(clock_source_);
     Append2LE(buf_.get() + 16, record_size);
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index 9176e89..cfa3691 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -136,6 +136,14 @@
     check(t.objectVar, objectValue, "Unsafe.putObject(Object, long, Object)");
     check(unsafe.getObject(t, objectOffset), objectValue, "Unsafe.getObject(Object, long)");
 
+    byte byteValue = 123;
+    Field byteField = TestClass.class.getDeclaredField("byteVar");
+    long byteOffset = unsafe.objectFieldOffset(byteField);
+    check(unsafe.getByte(t, byteOffset), 0, "Unsafe.getByte(Object, long) - initial");
+    unsafe.putByte(t, byteOffset, byteValue);
+    check(t.byteVar, byteValue, "Unsafe.putByte(Object, long, byte)");
+    check(unsafe.getByte(t, byteOffset), byteValue, "Unsafe.getByte(Object, long)");
+
     if (unsafe.compareAndSwapInt(t, intOffset, 0, 1)) {
       System.out.println("Unexpectedly succeeding compareAndSwapInt(t, intOffset, 0, 1)");
     }
@@ -288,6 +296,7 @@
     public int intVar = 0;
     public long longVar = 0;
     public Object objectVar = null;
+    public byte byteVar = 0;
   }
 
   private static class TestVolatileClass {
diff --git a/test/1911-get-local-var-table/src/art/Test1911.java b/test/1911-get-local-var-table/src/art/Test1911.java
index 4dd9054..3e2eec2 100644
--- a/test/1911-get-local-var-table/src/art/Test1911.java
+++ b/test/1911-get-local-var-table/src/art/Test1911.java
@@ -18,8 +18,10 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
+import java.lang.Integer;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Base64;
 import java.util.HashSet;
 import java.util.Set;
@@ -27,8 +29,8 @@
 public class Test1911 {
   // Class/dex file containing the following class.
   //
-  // CLASS_BYTES generated with java version 1.8.0_45: javac -g art/Target.java
-  // DEX_BYTES generated with dx version 1.14: dx --dex --output=./classes.dex art/Target.class
+  // CLASS_BYTES generated with java version 17.0.4.1: javac -g art/Target.java
+  // DEX_BYTES generated with d8 version 8.3.7-dev: d8 --debug art/Target.class
   //
   // package art;
   // import java.util.ArrayList;
@@ -53,58 +55,76 @@
   //     long q = 3 * p;
   //     doNothing(p, q, o, i);
   //   }
+  //   public void testGenericParameters(ArrayList<Integer> array, int i, Integer val) {
+  //     array.set(i, val);
+  //   }
   // }
   public static byte[] CLASS_BYTES = Base64.getDecoder().decode(
-    "yv66vgAAADQARgoABAAuCQANAC8KAA0AMAcAMQY/0zMzMzMzMwoAMgAzCgA0ADUHADYKAAkALgoA" +
-    "NwA4CgA5ADoHADsBAAN6enoBAAFJAQAGPGluaXQ+AQAEKEkpVgEABENvZGUBAA9MaW5lTnVtYmVy" +
-    "VGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAMTGFydC9UYXJnZXQ7AQADeHh4AQAB" +
-    "cQEACWRvTm90aGluZwEAFihbTGphdmEvbGFuZy9PYmplY3Q7KVYBAARvYmpzAQATW0xqYXZhL2xh" +
-    "bmcvT2JqZWN0OwEAC2RvU29tZXRoaW5nAQABRgEAAWkBAAFEAQABegEAAXgBAAF5AQABbwEAEkxq" +
-    "YXZhL2xhbmcvT2JqZWN0OwEAFUxqYXZhL3V0aWwvQXJyYXlMaXN0OwEAAXABAAFKAQAWTG9jYWxW" +
-    "YXJpYWJsZVR5cGVUYWJsZQEAKkxqYXZhL3V0aWwvQXJyYXlMaXN0PExqYXZhL2xhbmcvSW50ZWdl" +
-    "cjs+OwEADVN0YWNrTWFwVGFibGUBAApTb3VyY2VGaWxlAQALVGFyZ2V0LmphdmEMABAAPAwADgAP" +
-    "DAAZABoBABBqYXZhL2xhbmcvT2JqZWN0BwA9DAA+AD8HAEAMAD4AQQEAE2phdmEvdXRpbC9BcnJh" +
-    "eUxpc3QHAEIMAD4AQwcARAwAPgBFAQAKYXJ0L1RhcmdldAEAAygpVgEAD2phdmEvbGFuZy9GbG9h" +
-    "dAEAB3ZhbHVlT2YBABQoRilMamF2YS9sYW5nL0Zsb2F0OwEAEGphdmEvbGFuZy9Eb3VibGUBABUo" +
-    "RClMamF2YS9sYW5nL0RvdWJsZTsBABFqYXZhL2xhbmcvSW50ZWdlcgEAFihJKUxqYXZhL2xhbmcv" +
-    "SW50ZWdlcjsBAA5qYXZhL2xhbmcvTG9uZwEAEyhKKUxqYXZhL2xhbmcvTG9uZzsAIQANAAQAAAAB" +
-    "AAEADgAPAAAAAwABABAAEQABABIAAABYAAIAAwAAAA4qtwABGwdoPSoctQACsQAAAAIAEwAAABIA" +
-    "BAAAAAUABAAGAAgABwANAAgAFAAAACAAAwAAAA4AFQAWAAAAAAAOABcADwABAAgABgAYAA8AAgCJ" +
-    "ABkAGgABABIAAAAvAAEAAQAAAAUquAADsQAAAAIAEwAAAAYAAQAAAAkAFAAAAAwAAQAAAAUAGwAc" +
-    "AAAAAQAdABEAAQASAAABWAAFAAgAAACCBL0ABFkDKlO4AAMbBmA9Az4dHBtoogAvHB1khjgEFAAF" +
-    "FwSNazkFBb0ABFkDFwS4AAdTWQQYBbgACFO4AAOEAwGn/9C7AARZtwABTrsACVm3AAo6BAcbgDYF" +
-    "BhUFaIU3Bge9AARZAxUFuAALU1kEFga4AAxTWQUtU1kGGQRTuAADsQAAAAQAEwAAADYADQAAAAsA" +
-    "CwAMAA8ADQAYAA4AHgAPACcAEAA+AA0ARAASAEwAEwBVABQAWgAVAGEAFgCBABcAFAAAAGYACgAe" +
-    "ACAAGAAeAAQAJwAXAB8AIAAFABEAMwAhAA8AAwAAAIIAFQAWAAAAAACCACIADwABAA8AcwAjAA8A" +
-    "AgBMADYAJAAlAAMAVQAtAB8AJgAEAFoAKAAnAA8ABQBhACEAGAAoAAYAKQAAAAwAAQBVAC0AHwAq" +
-    "AAQAKwAAAAoAAv0AEQEB+gAyAAEALAAAAAIALQ==");
+      "yv66vgAAADcAUQoABAA2CQAOADcKAA4AOAcAOQY/0zMzMzMzMwoAOgA7CgA8AD0HAD4KAAkANgoA" +
+      "PwBACgBBAEIKAAkAQwcARAEAA3p6egEAAUkBAAY8aW5pdD4BAAQoSSlWAQAEQ29kZQEAD0xpbmVO" +
+      "dW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAxMYXJ0L1RhcmdldDsBAAN4" +
+      "eHgBAAFxAQAJZG9Ob3RoaW5nAQAWKFtMamF2YS9sYW5nL09iamVjdDspVgEABG9ianMBABNbTGph" +
+      "dmEvbGFuZy9PYmplY3Q7AQALZG9Tb21ldGhpbmcBAAFGAQABaQEAAUQBAAF6AQABeAEAAXkBAAFv" +
+      "AQASTGphdmEvbGFuZy9PYmplY3Q7AQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQABcAEAAUoBABZM" +
+      "b2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAqTGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvbGFuZy9J" +
+      "bnRlZ2VyOz47AQANU3RhY2tNYXBUYWJsZQEAFXRlc3RHZW5lcmljUGFyYW1ldGVycwEALChMamF2" +
+      "YS91dGlsL0FycmF5TGlzdDtJTGphdmEvbGFuZy9JbnRlZ2VyOylWAQAFYXJyYXkBAAN2YWwBABNM" +
+      "amF2YS9sYW5nL0ludGVnZXI7AQAJU2lnbmF0dXJlAQBBKExqYXZhL3V0aWwvQXJyYXlMaXN0PExq" +
+      "YXZhL2xhbmcvSW50ZWdlcjs+O0lMamF2YS9sYW5nL0ludGVnZXI7KVYBAApTb3VyY2VGaWxlAQAL" +
+      "VGFyZ2V0LmphdmEMABEARQwADwAQDAAaABsBABBqYXZhL2xhbmcvT2JqZWN0BwBGDABHAEgHAEkM" +
+      "AEcASgEAE2phdmEvdXRpbC9BcnJheUxpc3QHAEsMAEcATAcATQwARwBODABPAFABAAphcnQvVGFy" +
+      "Z2V0AQADKClWAQAPamF2YS9sYW5nL0Zsb2F0AQAHdmFsdWVPZgEAFChGKUxqYXZhL2xhbmcvRmxv" +
+      "YXQ7AQAQamF2YS9sYW5nL0RvdWJsZQEAFShEKUxqYXZhL2xhbmcvRG91YmxlOwEAEWphdmEvbGFu" +
+      "Zy9JbnRlZ2VyAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEADmphdmEvbGFuZy9Mb25nAQATKEop" +
+      "TGphdmEvbGFuZy9Mb25nOwEAA3NldAEAJyhJTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcv" +
+      "T2JqZWN0OwAhAA4ABAAAAAEAAQAPABAAAAAEAAEAEQASAAEAEwAAAFgAAgADAAAADiq3AAEbB2g9" +
+      "Khy1AAKxAAAAAgAUAAAAEgAEAAAACAAEAAkACAAKAA0ACwAVAAAAIAADAAAADgAWABcAAAAAAA4A" +
+      "GAAQAAEACAAGABkAEAACAIkAGgAbAAEAEwAAAC8AAQABAAAABSq4AAOxAAAAAgAUAAAABgABAAAA" +
+      "DQAVAAAADAABAAAABQAcAB0AAAABAB4AEgABABMAAAFYAAUACAAAAIIEvQAEWQMqU7gAAxsGYD0D" +
+      "Ph0cG2iiAC8cHWSGOAQUAAUXBI1rOQUFvQAEWQMXBLgAB1NZBBgFuAAIU7gAA4QDAaf/0LsABFm3" +
+      "AAFOuwAJWbcACjoEBxuANgUGFQVohTcGB70ABFkDFQW4AAtTWQQWBrgADFNZBS1TWQYZBFO4AAOx" +
+      "AAAABAAUAAAANgANAAAAEAALABEADwASABgAEwAeABQAJwAVAD4AEgBEABcATAAYAFUAGQBaABoA" +
+      "YQAbAIEAHAAVAAAAZgAKAB4AIAAZAB8ABAAnABcAIAAhAAUAEQAzACIAEAADAAAAggAWABcAAAAA" +
+      "AIIAIwAQAAEADwBzACQAEAACAEwANgAlACYAAwBVAC0AIAAnAAQAWgAoACgAEAAFAGEAIQAZACkA" +
+      "BgAqAAAADAABAFUALQAgACsABAAsAAAACgAC/QARAQH6ADIAAQAtAC4AAgATAAAAZgADAAQAAAAI" +
+      "KxwttgANV7EAAAADABQAAAAKAAIAAAAfAAcAIAAVAAAAKgAEAAAACAAWABcAAAAAAAgALwAnAAEA" +
+      "AAAIACAAEAACAAAACAAwADEAAwAqAAAADAABAAAACAAvACsAAQAyAAAAAgAzAAEANAAAAAIANQ==");
   public static byte[] DEX_BYTES = Base64.getDecoder().decode(
-    "ZGV4CjAzNQCQtgjEV631Ma/btYyIy2IzqHWNN+nZiwl0BQAAcAAAAHhWNBIAAAAAAAAAANQEAAAk" +
-    "AAAAcAAAAA0AAAAAAQAABwAAADQBAAABAAAAiAEAAAkAAACQAQAAAQAAANgBAAB8AwAA+AEAAB4D" +
-    "AAAmAwAAKQMAACwDAAAvAwAAMgMAADYDAAA6AwAAPgMAAEIDAABQAwAAZAMAAHcDAACMAwAAngMA" +
-    "ALIDAADJAwAA9QMAAAIEAAAFBAAACQQAAA0EAAAiBAAALQQAADoEAAA9BAAAQAQAAEYEAABJBAAA" +
-    "TAQAAFIEAABbBAAAXgQAAGMEAABmBAAAaQQAAAEAAAACAAAAAwAAAAQAAAAJAAAACgAAAAsAAAAM" +
-    "AAAADQAAAA4AAAAPAAAAEgAAABUAAAAFAAAABQAAAPgCAAAGAAAABgAAAAADAAAHAAAABwAAAAgD" +
-    "AAAIAAAACAAAABADAAASAAAACwAAAAAAAAATAAAACwAAAAgDAAAUAAAACwAAABgDAAAEAAIAIwAA" +
-    "AAQABQAAAAAABAAGABYAAAAEAAUAFwAAAAUAAAAeAAAABgABAB4AAAAHAAIAHgAAAAgAAwAeAAAA" +
-    "CQAEAAAAAAAKAAQAAAAAAAQAAAABAAAACQAAAAAAAAARAAAAAAAAAL4EAAAAAAAAAwACAAEAAABu" +
-    "BAAACAAAAHAQBwABANoAAgRZEAAADgABAAEAAQAAAHsEAAAEAAAAcRABAAAADgAQAAIAAgAAAIEE" +
-    "AABcAAAAEhkjmQwAEgpNDgkKcRABAAkA2AUPAxIIkgkFDzWYJACRCQUIgpYYCjMzMzMzM9M/iWyt" +
-    "AAoMEikjmQwAEgpxEAQABgAMC00LCQoSGnEgAwAQAAwLTQsJCnEQAQAJANgICAEo2yIDCQBwEAcA" +
-    "AwAiAgoAcBAIAAIA3gQPBNoJBAOBlhJJI5kMABIKcRAFAAQADAtNCwkKEhpxIAYAdgAMC00LCQoS" +
-    "Kk0DCQoSOk0CCQpxEAEACQAOAAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAwA" +
-    "Bjxpbml0PgABRAABRgABSQABSgACTEQAAkxGAAJMSQACTEoADExhcnQvVGFyZ2V0OwASTGphdmEv" +
-    "bGFuZy9Eb3VibGU7ABFMamF2YS9sYW5nL0Zsb2F0OwATTGphdmEvbGFuZy9JbnRlZ2VyOwAQTGph" +
-    "dmEvbGFuZy9Mb25nOwASTGphdmEvbGFuZy9PYmplY3Q7ABVMamF2YS91dGlsL0FycmF5TGlzdDsA" +
-    "KkxqYXZhL3V0aWwvQXJyYXlMaXN0PExqYXZhL2xhbmcvSW50ZWdlcjs+OwALVGFyZ2V0LmphdmEA" +
-    "AVYAAlZJAAJWTAATW0xqYXZhL2xhbmcvT2JqZWN0OwAJZG9Ob3RoaW5nAAtkb1NvbWV0aGluZwAB" +
-    "aQABbwAEb2JqcwABcAABcQAEdGhpcwAHdmFsdWVPZgABeAADeHh4AAF5AAF6AAN6enoABQEhBw48" +
-    "LQMAHQMtAAkBGwcOAAsBIAcOli0DBSIDAQEDCCMDSzwDBh0ChwMAGQEBFAtABQAFBloDAxoKWgQC" +
-    "GQsRLQMEHAM8AwYdBAEaDwAAAQIBAAEAgYAE+AMBiQGYBAIBsAQADQAAAAAAAAABAAAAAAAAAAEA" +
-    "AAAkAAAAcAAAAAIAAAANAAAAAAEAAAMAAAAHAAAANAEAAAQAAAABAAAAiAEAAAUAAAAJAAAAkAEA" +
-    "AAYAAAABAAAA2AEAAAEgAAADAAAA+AEAAAEQAAAFAAAA+AIAAAIgAAAkAAAAHgMAAAMgAAADAAAA" +
-    "bgQAAAAgAAABAAAAvgQAAAAQAAABAAAA1AQAAA==");
-
+      "ZGV4CjAzNQAALyjG3vy0POIlfGUh9Q7yf3NFwlp6VbWoBwAAcAAAAHhWNBIAAAAAAAAAAOQGAAAz" +
+      "AAAAcAAAAA8AAAA8AQAACgAAAHgBAAABAAAA8AEAAAwAAAD4AQAAAQAAAFgCAAAwBQAAeAIAACIE" +
+      "AAAlBAAAKQQAADEEAAA2BAAAOQQAADwEAAA/BAAAQgQAAEYEAABKBAAATgQAAFMEAABXBAAAZQQA" +
+      "AIQEAACYBAAAqwQAAMAEAADSBAAA5gQAAP0EAAAUBQAAQAUAAE0FAABQBQAAVAUAAFgFAABeBQAA" +
+      "YQUAAGUFAAB6BQAAgQUAAIwFAACZBQAAnAUAAKMFAACmBQAArAUAAK8FAACyBQAAtwUAAM4FAADT" +
+      "BQAA2gUAAOMFAADmBQAA6wUAAO4FAADxBQAA9gUAAAQAAAAFAAAABgAAAAcAAAANAAAADgAAAA8A" +
+      "AAAQAAAAEQAAABIAAAATAAAAFAAAABgAAAAcAAAAHgAAAAgAAAAGAAAA6AMAAAkAAAAHAAAA8AMA" +
+      "AAoAAAAIAAAA+AMAAAwAAAAJAAAAAAQAAAsAAAAKAAAACAQAABgAAAAMAAAAAAAAABkAAAAMAAAA" +
+      "+AMAABsAAAAMAAAAEAQAABoAAAAMAAAAHAQAAB0AAAANAAAA6AMAAAQAAgAxAAAABAAGAAIAAAAE" +
+      "AAgAIAAAAAQABgAhAAAABAAHACkAAAAGAAkAIwAAAAYAAAAsAAAABwABACwAAAAIAAIALAAAAAkA" +
+      "AwAsAAAACgAFAAIAAAALAAUAAgAAAAsABAAoAAAABAAAAAEAAAAKAAAAAAAAABcAAADMBgAApgYA" +
+      "AAAAAAADAAIAAQAAAIwDAAAIAAAAcBAJAAEA2gACBFkQAAAOAAEAAQABAAAAmAMAAAQAAABxEAEA" +
+      "AAAOAA4AAgACAAAAnQMAAFoAAAASECMBDgASAk0MAQJxEAEAAQDYAQ0DEgOSBAENEiU1QyQAkQQB" +
+      "A4JEGAYzMzMzMzPTP4lIcSAEAJgArQgIBnEQBgAEAAwGcSAFAJgADAcjVQ4ATQYFAk0HBQBxEAEA" +
+      "BQDYAwMBKNoiAwoAcBAJAAMAIgQLAHAQCgAEAN4GDQTaBwYDgXdxEAcABgAMCXEgCACHAAwKEksj" +
+      "uw4ATQkLAk0KCwBNAwsFEjBNBAsAcRABAAsADgAEAAQAAwAAANsDAAAEAAAAbjALACEDDgAIAS8O" +
+      "PC0DACgDLQANASYOABABLg6WLQMBMAMBAQMDMQNaPAMEKAK0AwgjAQERCwUEBQhABQNaAwMlC1oE" +
+      "BCMMFy0DBicDPAMHKAQBFw8AHwMAIysOBAEgDBc8AAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEA" +
+      "AAADAAAAAgAAAAIACgADAAAACwACAAgAAAABAAAADgABKAACKVYABjxpbml0PgADPjtJAAFEAAFG" +
+      "AAFJAAFKAAJMRAACTEYAAkxJAANMSUwAAkxKAAxMYXJ0L1RhcmdldDsAHUxkYWx2aWsvYW5ub3Rh" +
+      "dGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL0RvdWJsZTsAEUxqYXZhL2xhbmcvRmxvYXQ7ABNM" +
+      "amF2YS9sYW5nL0ludGVnZXI7ABBMamF2YS9sYW5nL0xvbmc7ABJMamF2YS9sYW5nL09iamVjdDsA" +
+      "FUxqYXZhL3V0aWwvQXJyYXlMaXN0OwAVTGphdmEvdXRpbC9BcnJheUxpc3Q8ACpMamF2YS91dGls" +
+      "L0FycmF5TGlzdDxMamF2YS9sYW5nL0ludGVnZXI7PjsAC1RhcmdldC5qYXZhAAFWAAJWSQACVkwA" +
+      "BFZMSUwAAVoAAlpEABNbTGphdmEvbGFuZy9PYmplY3Q7AAVhcnJheQAJZG9Ob3RoaW5nAAtkb1Nv" +
+      "bWV0aGluZwABaQAFaXNOYU4AAW8ABG9ianMAAXAAAXEAA3NldAAVdGVzdEdlbmVyaWNQYXJhbWV0" +
+      "ZXJzAAN2YWwABXZhbHVlAAd2YWx1ZU9mAAF4AAN4eHgAAXkAAXoAA3p6egCbAX5+RDh7ImJhY2tl" +
+      "bmQiOiJkZXgiLCJjb21waWxhdGlvbi1tb2RlIjoiZGVidWciLCJoYXMtY2hlY2tzdW1zIjpmYWxz" +
+      "ZSwibWluLWFwaSI6MSwic2hhLTEiOiIzMTAxYWQ2Zjc0ZWUyMzI1MjhkZmM2NmEyNjE3YTkzODM4" +
+      "NGU2NmVhIiwidmVyc2lvbiI6IjguMy43LWRldiJ9AAIFASscBhcAFxUXERcDFxEXAQABAgIAAQCB" +
+      "gAT4BAGJAZgFAgGwBQEB9AYAAAAAAAEAAACUBgAAwAYAAAAAAAABAAAAAAAAAAMAAADEBgAAEAAA" +
+      "AAAAAAABAAAAAAAAAAEAAAAzAAAAcAAAAAIAAAAPAAAAPAEAAAMAAAAKAAAAeAEAAAQAAAABAAAA" +
+      "8AEAAAUAAAAMAAAA+AEAAAYAAAABAAAAWAIAAAEgAAAEAAAAeAIAAAMgAAAEAAAAjAMAAAEQAAAH" +
+      "AAAA6AMAAAIgAAAzAAAAIgQAAAQgAAABAAAAlAYAAAAgAAABAAAApgYAAAMQAAACAAAAwAYAAAYg" +
+      "AAABAAAAzAYAAAAQAAABAAAA5AYAAA==");
 
   // The variables of the functions in the above Target class.
   public static Set<Locals.VariableDescription>[] CONSTRUCTOR_VARIABLES = new Set[] {
@@ -149,23 +169,49 @@
                                              4))),
       // ART Local variable table
       new HashSet<>(Arrays.asList(
-              new Locals.VariableDescription(19, 31, "q", "F", null, 6),
-              new Locals.VariableDescription(55, 37, "o", "Ljava/lang/Object;", null, 3),
-              new Locals.VariableDescription(0, 92, "this", "Lart/Target;", null, 14),
-              new Locals.VariableDescription(12, 80, "z", "I", null, 8),
-              new Locals.VariableDescription(11, 81, "y", "I", null, 5),
-              new Locals.VariableDescription(62, 30, "p", "I", null, 4),
-              new Locals.VariableDescription(0, 92, "x", "I", null, 15),
-              new Locals.VariableDescription(27, 23, "i", "D", null, 0),
-              new Locals.VariableDescription(65, 27, "q", "J", null, 6),
-              new Locals.VariableDescription(60,
-                                             32,
+              new Locals.VariableDescription(20, 28, "q", "F", null, 4),
+              new Locals.VariableDescription(56, 34, "o", "Ljava/lang/Object;", null, 3),
+              new Locals.VariableDescription(0, 90, "this", "Lart/Target;", null, 12),
+              new Locals.VariableDescription(12, 39, "z", "I", null, 3),
+              new Locals.VariableDescription(11, 79, "y", "I", null, 1),
+              new Locals.VariableDescription(63, 27, "p", "I", null, 6),
+              new Locals.VariableDescription(0, 90, "x", "I", null, 13),
+              new Locals.VariableDescription(31, 17, "i", "D", null, 8),
+              new Locals.VariableDescription(66, 24, "q", "J", null, 7),
+              new Locals.VariableDescription(61,
+                                             29,
                                              "i",
                                              "Ljava/util/ArrayList;",
                                              "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
-                                             2))),
+                                             4))),
   };
 
+  public static Set<Locals.VariableDescription>[] TEST_GENERIC_PARAMETERS_VARIABLES = new Set[] {
+      // RI Local variable table
+      new HashSet<>(Arrays.asList(
+              new Locals.VariableDescription(0, 8, "this", "Lart/Target;", null, 0),
+              new Locals.VariableDescription(0,
+                                             8,
+                                             "array",
+                                             "Ljava/util/ArrayList;",
+                                             "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
+                                             1),
+              new Locals.VariableDescription(0, 8, "i", "I", null, 2),
+              new Locals.VariableDescription(0, 8, "val", "Ljava/lang/Integer;", null, 3))),
+      // ART Local variable table
+      new HashSet<>(Arrays.asList(
+              new Locals.VariableDescription(0, 4, "this", "Lart/Target;", null, 0),
+              new Locals.VariableDescription(0,
+                                             4,
+                                             "array",
+                                             "Ljava/util/ArrayList;",
+                                             "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
+                                             1),
+              new Locals.VariableDescription(0, 4, "i", "I", null, 2),
+              new Locals.VariableDescription(0, 4, "val", "Ljava/lang/Integer;", null, 3))),
+  };
+
+
   // Get a classloader that can load the Target class.
   public static ClassLoader getClassLoader() throws Exception {
     try {
@@ -213,6 +259,9 @@
             DO_NOTHING_VARIABLES);
     CheckLocalVariableTable(target.getDeclaredMethod("doSomething", Integer.TYPE),
             DO_SOMETHING_VARIABLES);
+    CheckLocalVariableTable(target.getDeclaredMethod("testGenericParameters",
+            (new ArrayList<Integer>(0)).getClass(), Integer.TYPE, (new Integer(0)).getClass()),
+            TEST_GENERIC_PARAMETERS_VARIABLES);
   }
 }
 
diff --git a/test/dexpreopt/dexpreopt_test.cc b/test/dexpreopt/dexpreopt_test.cc
index 9641e0a..eac84f5 100644
--- a/test/dexpreopt/dexpreopt_test.cc
+++ b/test/dexpreopt/dexpreopt_test.cc
@@ -198,12 +198,7 @@
   if (pids.size() != 1) {
     return Errorf("There should be exactly one `system_server` process, found {}", pids.size());
   }
-  // Unlike boot images, app images don't get unmapped if the runtime rejects them in some cases
-  // (e.g., CLC mismatch). Therefore, we need to check the PROT_EXEC flag to ensure that they are
-  // valid.
-  // The ODEX files always contain executable code because system server jars are compiled with the
-  // "speed" filter.
-  return GetMappedFiles(pids[0], ".odex", PROT_EXEC);
+  return GetMappedFiles(pids[0], ".odex", PROT_READ);
 }
 
 TEST(DexpreoptTest, ForZygote) {
diff --git a/tools/build-linux-x86-host-tools.sh b/tools/build-linux-x86-host-tools.sh
new file mode 100755
index 0000000..c0483fa
--- /dev/null
+++ b/tools/build-linux-x86-host-tools.sh
@@ -0,0 +1,56 @@
+ #!/bin/bash
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+if [ ! -e 'build/make/core/Makefile' ]; then
+  echo "Script $0 needs to be run at the root of the android tree"
+  exit 1
+fi
+
+vars="$(build/soong/soong_ui.bash --dumpvars-mode --vars="OUT_DIR DIST_DIR")"
+# Assign to a variable and eval that, since bash ignores any error status from
+# the command substitution if it's directly on the eval line.
+eval $vars
+
+HOST_BINARIES=(
+  ${OUT_DIR}/host/linux-x86/bin/dex2oat64
+  ${OUT_DIR}/host/linux-x86/bin/dex2oatd64
+  ${OUT_DIR}/host/linux-x86/bin/dex2oat
+  ${OUT_DIR}/host/linux-x86/bin/dex2oatd
+  ${OUT_DIR}/host/linux-x86/bin/deapexer
+  ${OUT_DIR}/host/linux-x86/bin/debugfs_static
+  ${OUT_DIR}/host/linux-x86/bin/oatdump
+)
+
+# Build statically linked musl binaries for linux-x86 hosts without the
+# standard glibc implementation.
+build/soong/soong_ui.bash --make-mode USE_HOST_MUSL=true BUILD_HOST_static=true ${HOST_BINARIES[*]}
+# Zip these binaries in a temporary file
+prebuilts/build-tools/linux-x86/bin/soong_zip -o "${DIST_DIR}/temp-host-tools.zip" \
+  -j ${HOST_BINARIES[*]/#/-f }
+
+# Build art_release.zip and copy only art jars in a temporary zip
+build/soong/soong_ui.bash --make-mode dist "${DIST_DIR}/art_release.zip"
+prebuilts/build-tools/linux-x86/bin/zip2zip -i "${DIST_DIR}/art_release.zip" \
+  -o "${DIST_DIR}/temp-art-jars.zip" "bootjars/*"
+
+# Merge both temporary zips into output zip
+prebuilts/build-tools/linux-x86/bin/merge_zips "${DIST_DIR}/art-host-tools-linux-x86.zip" \
+  "${DIST_DIR}/temp-host-tools.zip" "${DIST_DIR}/temp-art-jars.zip"
+
+# Delete temporary zips
+rm "${DIST_DIR}/temp-host-tools.zip" "${DIST_DIR}/temp-art-jars.zip"