Merge "Integrate dexfuzz with bisection search"
diff --git a/Android.mk b/Android.mk
index 0e6f3ce..2647268 100644
--- a/Android.mk
+++ b/Android.mk
@@ -443,6 +443,8 @@
                         $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
                         $(TARGET_CORE_IMG_OUT_BASE).art \
                         $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
+	# remove libartd.so from public.libraries.txt because golem builds won't have it.
 
 ########################################################################
 # Phony target for building what go/lem requires on host.
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index dd19888..014a2b3 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -17,7 +17,7 @@
 art_cc_library {
     name: "libartbenchmark",
     host_supported: true,
-    defaults: ["art_defaults", "art_debug_defaults"],
+    defaults: ["art_defaults" ],
     srcs: [
         "jni_loader.cc",
         "jobject-benchmark/jobject_benchmark.cc",
diff --git a/benchmark/const-string/info.txt b/benchmark/const-string/info.txt
new file mode 100644
index 0000000..78f39d2
--- /dev/null
+++ b/benchmark/const-string/info.txt
@@ -0,0 +1 @@
+Benchmarks for repeating const-string instructions in a loop.
diff --git a/benchmark/const-string/src/ConstStringBenchmark.java b/benchmark/const-string/src/ConstStringBenchmark.java
new file mode 100644
index 0000000..2beb0a4
--- /dev/null
+++ b/benchmark/const-string/src/ConstStringBenchmark.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class ConstStringBenchmark {
+    // Initialize 1025 strings with consecutive string indexes in the dex file.
+    // The tests below rely on the knowledge that ART uses the low 10 bits
+    // of the string index as the hash into DexCache strings array.
+    public static final String string_0000 = "TestString_0000";
+    public static final String string_0001 = "TestString_0001";
+    public static final String string_0002 = "TestString_0002";
+    public static final String string_0003 = "TestString_0003";
+    public static final String string_0004 = "TestString_0004";
+    public static final String string_0005 = "TestString_0005";
+    public static final String string_0006 = "TestString_0006";
+    public static final String string_0007 = "TestString_0007";
+    public static final String string_0008 = "TestString_0008";
+    public static final String string_0009 = "TestString_0009";
+    public static final String string_0010 = "TestString_0010";
+    public static final String string_0011 = "TestString_0011";
+    public static final String string_0012 = "TestString_0012";
+    public static final String string_0013 = "TestString_0013";
+    public static final String string_0014 = "TestString_0014";
+    public static final String string_0015 = "TestString_0015";
+    public static final String string_0016 = "TestString_0016";
+    public static final String string_0017 = "TestString_0017";
+    public static final String string_0018 = "TestString_0018";
+    public static final String string_0019 = "TestString_0019";
+    public static final String string_0020 = "TestString_0020";
+    public static final String string_0021 = "TestString_0021";
+    public static final String string_0022 = "TestString_0022";
+    public static final String string_0023 = "TestString_0023";
+    public static final String string_0024 = "TestString_0024";
+    public static final String string_0025 = "TestString_0025";
+    public static final String string_0026 = "TestString_0026";
+    public static final String string_0027 = "TestString_0027";
+    public static final String string_0028 = "TestString_0028";
+    public static final String string_0029 = "TestString_0029";
+    public static final String string_0030 = "TestString_0030";
+    public static final String string_0031 = "TestString_0031";
+    public static final String string_0032 = "TestString_0032";
+    public static final String string_0033 = "TestString_0033";
+    public static final String string_0034 = "TestString_0034";
+    public static final String string_0035 = "TestString_0035";
+    public static final String string_0036 = "TestString_0036";
+    public static final String string_0037 = "TestString_0037";
+    public static final String string_0038 = "TestString_0038";
+    public static final String string_0039 = "TestString_0039";
+    public static final String string_0040 = "TestString_0040";
+    public static final String string_0041 = "TestString_0041";
+    public static final String string_0042 = "TestString_0042";
+    public static final String string_0043 = "TestString_0043";
+    public static final String string_0044 = "TestString_0044";
+    public static final String string_0045 = "TestString_0045";
+    public static final String string_0046 = "TestString_0046";
+    public static final String string_0047 = "TestString_0047";
+    public static final String string_0048 = "TestString_0048";
+    public static final String string_0049 = "TestString_0049";
+    public static final String string_0050 = "TestString_0050";
+    public static final String string_0051 = "TestString_0051";
+    public static final String string_0052 = "TestString_0052";
+    public static final String string_0053 = "TestString_0053";
+    public static final String string_0054 = "TestString_0054";
+    public static final String string_0055 = "TestString_0055";
+    public static final String string_0056 = "TestString_0056";
+    public static final String string_0057 = "TestString_0057";
+    public static final String string_0058 = "TestString_0058";
+    public static final String string_0059 = "TestString_0059";
+    public static final String string_0060 = "TestString_0060";
+    public static final String string_0061 = "TestString_0061";
+    public static final String string_0062 = "TestString_0062";
+    public static final String string_0063 = "TestString_0063";
+    public static final String string_0064 = "TestString_0064";
+    public static final String string_0065 = "TestString_0065";
+    public static final String string_0066 = "TestString_0066";
+    public static final String string_0067 = "TestString_0067";
+    public static final String string_0068 = "TestString_0068";
+    public static final String string_0069 = "TestString_0069";
+    public static final String string_0070 = "TestString_0070";
+    public static final String string_0071 = "TestString_0071";
+    public static final String string_0072 = "TestString_0072";
+    public static final String string_0073 = "TestString_0073";
+    public static final String string_0074 = "TestString_0074";
+    public static final String string_0075 = "TestString_0075";
+    public static final String string_0076 = "TestString_0076";
+    public static final String string_0077 = "TestString_0077";
+    public static final String string_0078 = "TestString_0078";
+    public static final String string_0079 = "TestString_0079";
+    public static final String string_0080 = "TestString_0080";
+    public static final String string_0081 = "TestString_0081";
+    public static final String string_0082 = "TestString_0082";
+    public static final String string_0083 = "TestString_0083";
+    public static final String string_0084 = "TestString_0084";
+    public static final String string_0085 = "TestString_0085";
+    public static final String string_0086 = "TestString_0086";
+    public static final String string_0087 = "TestString_0087";
+    public static final String string_0088 = "TestString_0088";
+    public static final String string_0089 = "TestString_0089";
+    public static final String string_0090 = "TestString_0090";
+    public static final String string_0091 = "TestString_0091";
+    public static final String string_0092 = "TestString_0092";
+    public static final String string_0093 = "TestString_0093";
+    public static final String string_0094 = "TestString_0094";
+    public static final String string_0095 = "TestString_0095";
+    public static final String string_0096 = "TestString_0096";
+    public static final String string_0097 = "TestString_0097";
+    public static final String string_0098 = "TestString_0098";
+    public static final String string_0099 = "TestString_0099";
+    public static final String string_0100 = "TestString_0100";
+    public static final String string_0101 = "TestString_0101";
+    public static final String string_0102 = "TestString_0102";
+    public static final String string_0103 = "TestString_0103";
+    public static final String string_0104 = "TestString_0104";
+    public static final String string_0105 = "TestString_0105";
+    public static final String string_0106 = "TestString_0106";
+    public static final String string_0107 = "TestString_0107";
+    public static final String string_0108 = "TestString_0108";
+    public static final String string_0109 = "TestString_0109";
+    public static final String string_0110 = "TestString_0110";
+    public static final String string_0111 = "TestString_0111";
+    public static final String string_0112 = "TestString_0112";
+    public static final String string_0113 = "TestString_0113";
+    public static final String string_0114 = "TestString_0114";
+    public static final String string_0115 = "TestString_0115";
+    public static final String string_0116 = "TestString_0116";
+    public static final String string_0117 = "TestString_0117";
+    public static final String string_0118 = "TestString_0118";
+    public static final String string_0119 = "TestString_0119";
+    public static final String string_0120 = "TestString_0120";
+    public static final String string_0121 = "TestString_0121";
+    public static final String string_0122 = "TestString_0122";
+    public static final String string_0123 = "TestString_0123";
+    public static final String string_0124 = "TestString_0124";
+    public static final String string_0125 = "TestString_0125";
+    public static final String string_0126 = "TestString_0126";
+    public static final String string_0127 = "TestString_0127";
+    public static final String string_0128 = "TestString_0128";
+    public static final String string_0129 = "TestString_0129";
+    public static final String string_0130 = "TestString_0130";
+    public static final String string_0131 = "TestString_0131";
+    public static final String string_0132 = "TestString_0132";
+    public static final String string_0133 = "TestString_0133";
+    public static final String string_0134 = "TestString_0134";
+    public static final String string_0135 = "TestString_0135";
+    public static final String string_0136 = "TestString_0136";
+    public static final String string_0137 = "TestString_0137";
+    public static final String string_0138 = "TestString_0138";
+    public static final String string_0139 = "TestString_0139";
+    public static final String string_0140 = "TestString_0140";
+    public static final String string_0141 = "TestString_0141";
+    public static final String string_0142 = "TestString_0142";
+    public static final String string_0143 = "TestString_0143";
+    public static final String string_0144 = "TestString_0144";
+    public static final String string_0145 = "TestString_0145";
+    public static final String string_0146 = "TestString_0146";
+    public static final String string_0147 = "TestString_0147";
+    public static final String string_0148 = "TestString_0148";
+    public static final String string_0149 = "TestString_0149";
+    public static final String string_0150 = "TestString_0150";
+    public static final String string_0151 = "TestString_0151";
+    public static final String string_0152 = "TestString_0152";
+    public static final String string_0153 = "TestString_0153";
+    public static final String string_0154 = "TestString_0154";
+    public static final String string_0155 = "TestString_0155";
+    public static final String string_0156 = "TestString_0156";
+    public static final String string_0157 = "TestString_0157";
+    public static final String string_0158 = "TestString_0158";
+    public static final String string_0159 = "TestString_0159";
+    public static final String string_0160 = "TestString_0160";
+    public static final String string_0161 = "TestString_0161";
+    public static final String string_0162 = "TestString_0162";
+    public static final String string_0163 = "TestString_0163";
+    public static final String string_0164 = "TestString_0164";
+    public static final String string_0165 = "TestString_0165";
+    public static final String string_0166 = "TestString_0166";
+    public static final String string_0167 = "TestString_0167";
+    public static final String string_0168 = "TestString_0168";
+    public static final String string_0169 = "TestString_0169";
+    public static final String string_0170 = "TestString_0170";
+    public static final String string_0171 = "TestString_0171";
+    public static final String string_0172 = "TestString_0172";
+    public static final String string_0173 = "TestString_0173";
+    public static final String string_0174 = "TestString_0174";
+    public static final String string_0175 = "TestString_0175";
+    public static final String string_0176 = "TestString_0176";
+    public static final String string_0177 = "TestString_0177";
+    public static final String string_0178 = "TestString_0178";
+    public static final String string_0179 = "TestString_0179";
+    public static final String string_0180 = "TestString_0180";
+    public static final String string_0181 = "TestString_0181";
+    public static final String string_0182 = "TestString_0182";
+    public static final String string_0183 = "TestString_0183";
+    public static final String string_0184 = "TestString_0184";
+    public static final String string_0185 = "TestString_0185";
+    public static final String string_0186 = "TestString_0186";
+    public static final String string_0187 = "TestString_0187";
+    public static final String string_0188 = "TestString_0188";
+    public static final String string_0189 = "TestString_0189";
+    public static final String string_0190 = "TestString_0190";
+    public static final String string_0191 = "TestString_0191";
+    public static final String string_0192 = "TestString_0192";
+    public static final String string_0193 = "TestString_0193";
+    public static final String string_0194 = "TestString_0194";
+    public static final String string_0195 = "TestString_0195";
+    public static final String string_0196 = "TestString_0196";
+    public static final String string_0197 = "TestString_0197";
+    public static final String string_0198 = "TestString_0198";
+    public static final String string_0199 = "TestString_0199";
+    public static final String string_0200 = "TestString_0200";
+    public static final String string_0201 = "TestString_0201";
+    public static final String string_0202 = "TestString_0202";
+    public static final String string_0203 = "TestString_0203";
+    public static final String string_0204 = "TestString_0204";
+    public static final String string_0205 = "TestString_0205";
+    public static final String string_0206 = "TestString_0206";
+    public static final String string_0207 = "TestString_0207";
+    public static final String string_0208 = "TestString_0208";
+    public static final String string_0209 = "TestString_0209";
+    public static final String string_0210 = "TestString_0210";
+    public static final String string_0211 = "TestString_0211";
+    public static final String string_0212 = "TestString_0212";
+    public static final String string_0213 = "TestString_0213";
+    public static final String string_0214 = "TestString_0214";
+    public static final String string_0215 = "TestString_0215";
+    public static final String string_0216 = "TestString_0216";
+    public static final String string_0217 = "TestString_0217";
+    public static final String string_0218 = "TestString_0218";
+    public static final String string_0219 = "TestString_0219";
+    public static final String string_0220 = "TestString_0220";
+    public static final String string_0221 = "TestString_0221";
+    public static final String string_0222 = "TestString_0222";
+    public static final String string_0223 = "TestString_0223";
+    public static final String string_0224 = "TestString_0224";
+    public static final String string_0225 = "TestString_0225";
+    public static final String string_0226 = "TestString_0226";
+    public static final String string_0227 = "TestString_0227";
+    public static final String string_0228 = "TestString_0228";
+    public static final String string_0229 = "TestString_0229";
+    public static final String string_0230 = "TestString_0230";
+    public static final String string_0231 = "TestString_0231";
+    public static final String string_0232 = "TestString_0232";
+    public static final String string_0233 = "TestString_0233";
+    public static final String string_0234 = "TestString_0234";
+    public static final String string_0235 = "TestString_0235";
+    public static final String string_0236 = "TestString_0236";
+    public static final String string_0237 = "TestString_0237";
+    public static final String string_0238 = "TestString_0238";
+    public static final String string_0239 = "TestString_0239";
+    public static final String string_0240 = "TestString_0240";
+    public static final String string_0241 = "TestString_0241";
+    public static final String string_0242 = "TestString_0242";
+    public static final String string_0243 = "TestString_0243";
+    public static final String string_0244 = "TestString_0244";
+    public static final String string_0245 = "TestString_0245";
+    public static final String string_0246 = "TestString_0246";
+    public static final String string_0247 = "TestString_0247";
+    public static final String string_0248 = "TestString_0248";
+    public static final String string_0249 = "TestString_0249";
+    public static final String string_0250 = "TestString_0250";
+    public static final String string_0251 = "TestString_0251";
+    public static final String string_0252 = "TestString_0252";
+    public static final String string_0253 = "TestString_0253";
+    public static final String string_0254 = "TestString_0254";
+    public static final String string_0255 = "TestString_0255";
+    public static final String string_0256 = "TestString_0256";
+    public static final String string_0257 = "TestString_0257";
+    public static final String string_0258 = "TestString_0258";
+    public static final String string_0259 = "TestString_0259";
+    public static final String string_0260 = "TestString_0260";
+    public static final String string_0261 = "TestString_0261";
+    public static final String string_0262 = "TestString_0262";
+    public static final String string_0263 = "TestString_0263";
+    public static final String string_0264 = "TestString_0264";
+    public static final String string_0265 = "TestString_0265";
+    public static final String string_0266 = "TestString_0266";
+    public static final String string_0267 = "TestString_0267";
+    public static final String string_0268 = "TestString_0268";
+    public static final String string_0269 = "TestString_0269";
+    public static final String string_0270 = "TestString_0270";
+    public static final String string_0271 = "TestString_0271";
+    public static final String string_0272 = "TestString_0272";
+    public static final String string_0273 = "TestString_0273";
+    public static final String string_0274 = "TestString_0274";
+    public static final String string_0275 = "TestString_0275";
+    public static final String string_0276 = "TestString_0276";
+    public static final String string_0277 = "TestString_0277";
+    public static final String string_0278 = "TestString_0278";
+    public static final String string_0279 = "TestString_0279";
+    public static final String string_0280 = "TestString_0280";
+    public static final String string_0281 = "TestString_0281";
+    public static final String string_0282 = "TestString_0282";
+    public static final String string_0283 = "TestString_0283";
+    public static final String string_0284 = "TestString_0284";
+    public static final String string_0285 = "TestString_0285";
+    public static final String string_0286 = "TestString_0286";
+    public static final String string_0287 = "TestString_0287";
+    public static final String string_0288 = "TestString_0288";
+    public static final String string_0289 = "TestString_0289";
+    public static final String string_0290 = "TestString_0290";
+    public static final String string_0291 = "TestString_0291";
+    public static final String string_0292 = "TestString_0292";
+    public static final String string_0293 = "TestString_0293";
+    public static final String string_0294 = "TestString_0294";
+    public static final String string_0295 = "TestString_0295";
+    public static final String string_0296 = "TestString_0296";
+    public static final String string_0297 = "TestString_0297";
+    public static final String string_0298 = "TestString_0298";
+    public static final String string_0299 = "TestString_0299";
+    public static final String string_0300 = "TestString_0300";
+    public static final String string_0301 = "TestString_0301";
+    public static final String string_0302 = "TestString_0302";
+    public static final String string_0303 = "TestString_0303";
+    public static final String string_0304 = "TestString_0304";
+    public static final String string_0305 = "TestString_0305";
+    public static final String string_0306 = "TestString_0306";
+    public static final String string_0307 = "TestString_0307";
+    public static final String string_0308 = "TestString_0308";
+    public static final String string_0309 = "TestString_0309";
+    public static final String string_0310 = "TestString_0310";
+    public static final String string_0311 = "TestString_0311";
+    public static final String string_0312 = "TestString_0312";
+    public static final String string_0313 = "TestString_0313";
+    public static final String string_0314 = "TestString_0314";
+    public static final String string_0315 = "TestString_0315";
+    public static final String string_0316 = "TestString_0316";
+    public static final String string_0317 = "TestString_0317";
+    public static final String string_0318 = "TestString_0318";
+    public static final String string_0319 = "TestString_0319";
+    public static final String string_0320 = "TestString_0320";
+    public static final String string_0321 = "TestString_0321";
+    public static final String string_0322 = "TestString_0322";
+    public static final String string_0323 = "TestString_0323";
+    public static final String string_0324 = "TestString_0324";
+    public static final String string_0325 = "TestString_0325";
+    public static final String string_0326 = "TestString_0326";
+    public static final String string_0327 = "TestString_0327";
+    public static final String string_0328 = "TestString_0328";
+    public static final String string_0329 = "TestString_0329";
+    public static final String string_0330 = "TestString_0330";
+    public static final String string_0331 = "TestString_0331";
+    public static final String string_0332 = "TestString_0332";
+    public static final String string_0333 = "TestString_0333";
+    public static final String string_0334 = "TestString_0334";
+    public static final String string_0335 = "TestString_0335";
+    public static final String string_0336 = "TestString_0336";
+    public static final String string_0337 = "TestString_0337";
+    public static final String string_0338 = "TestString_0338";
+    public static final String string_0339 = "TestString_0339";
+    public static final String string_0340 = "TestString_0340";
+    public static final String string_0341 = "TestString_0341";
+    public static final String string_0342 = "TestString_0342";
+    public static final String string_0343 = "TestString_0343";
+    public static final String string_0344 = "TestString_0344";
+    public static final String string_0345 = "TestString_0345";
+    public static final String string_0346 = "TestString_0346";
+    public static final String string_0347 = "TestString_0347";
+    public static final String string_0348 = "TestString_0348";
+    public static final String string_0349 = "TestString_0349";
+    public static final String string_0350 = "TestString_0350";
+    public static final String string_0351 = "TestString_0351";
+    public static final String string_0352 = "TestString_0352";
+    public static final String string_0353 = "TestString_0353";
+    public static final String string_0354 = "TestString_0354";
+    public static final String string_0355 = "TestString_0355";
+    public static final String string_0356 = "TestString_0356";
+    public static final String string_0357 = "TestString_0357";
+    public static final String string_0358 = "TestString_0358";
+    public static final String string_0359 = "TestString_0359";
+    public static final String string_0360 = "TestString_0360";
+    public static final String string_0361 = "TestString_0361";
+    public static final String string_0362 = "TestString_0362";
+    public static final String string_0363 = "TestString_0363";
+    public static final String string_0364 = "TestString_0364";
+    public static final String string_0365 = "TestString_0365";
+    public static final String string_0366 = "TestString_0366";
+    public static final String string_0367 = "TestString_0367";
+    public static final String string_0368 = "TestString_0368";
+    public static final String string_0369 = "TestString_0369";
+    public static final String string_0370 = "TestString_0370";
+    public static final String string_0371 = "TestString_0371";
+    public static final String string_0372 = "TestString_0372";
+    public static final String string_0373 = "TestString_0373";
+    public static final String string_0374 = "TestString_0374";
+    public static final String string_0375 = "TestString_0375";
+    public static final String string_0376 = "TestString_0376";
+    public static final String string_0377 = "TestString_0377";
+    public static final String string_0378 = "TestString_0378";
+    public static final String string_0379 = "TestString_0379";
+    public static final String string_0380 = "TestString_0380";
+    public static final String string_0381 = "TestString_0381";
+    public static final String string_0382 = "TestString_0382";
+    public static final String string_0383 = "TestString_0383";
+    public static final String string_0384 = "TestString_0384";
+    public static final String string_0385 = "TestString_0385";
+    public static final String string_0386 = "TestString_0386";
+    public static final String string_0387 = "TestString_0387";
+    public static final String string_0388 = "TestString_0388";
+    public static final String string_0389 = "TestString_0389";
+    public static final String string_0390 = "TestString_0390";
+    public static final String string_0391 = "TestString_0391";
+    public static final String string_0392 = "TestString_0392";
+    public static final String string_0393 = "TestString_0393";
+    public static final String string_0394 = "TestString_0394";
+    public static final String string_0395 = "TestString_0395";
+    public static final String string_0396 = "TestString_0396";
+    public static final String string_0397 = "TestString_0397";
+    public static final String string_0398 = "TestString_0398";
+    public static final String string_0399 = "TestString_0399";
+    public static final String string_0400 = "TestString_0400";
+    public static final String string_0401 = "TestString_0401";
+    public static final String string_0402 = "TestString_0402";
+    public static final String string_0403 = "TestString_0403";
+    public static final String string_0404 = "TestString_0404";
+    public static final String string_0405 = "TestString_0405";
+    public static final String string_0406 = "TestString_0406";
+    public static final String string_0407 = "TestString_0407";
+    public static final String string_0408 = "TestString_0408";
+    public static final String string_0409 = "TestString_0409";
+    public static final String string_0410 = "TestString_0410";
+    public static final String string_0411 = "TestString_0411";
+    public static final String string_0412 = "TestString_0412";
+    public static final String string_0413 = "TestString_0413";
+    public static final String string_0414 = "TestString_0414";
+    public static final String string_0415 = "TestString_0415";
+    public static final String string_0416 = "TestString_0416";
+    public static final String string_0417 = "TestString_0417";
+    public static final String string_0418 = "TestString_0418";
+    public static final String string_0419 = "TestString_0419";
+    public static final String string_0420 = "TestString_0420";
+    public static final String string_0421 = "TestString_0421";
+    public static final String string_0422 = "TestString_0422";
+    public static final String string_0423 = "TestString_0423";
+    public static final String string_0424 = "TestString_0424";
+    public static final String string_0425 = "TestString_0425";
+    public static final String string_0426 = "TestString_0426";
+    public static final String string_0427 = "TestString_0427";
+    public static final String string_0428 = "TestString_0428";
+    public static final String string_0429 = "TestString_0429";
+    public static final String string_0430 = "TestString_0430";
+    public static final String string_0431 = "TestString_0431";
+    public static final String string_0432 = "TestString_0432";
+    public static final String string_0433 = "TestString_0433";
+    public static final String string_0434 = "TestString_0434";
+    public static final String string_0435 = "TestString_0435";
+    public static final String string_0436 = "TestString_0436";
+    public static final String string_0437 = "TestString_0437";
+    public static final String string_0438 = "TestString_0438";
+    public static final String string_0439 = "TestString_0439";
+    public static final String string_0440 = "TestString_0440";
+    public static final String string_0441 = "TestString_0441";
+    public static final String string_0442 = "TestString_0442";
+    public static final String string_0443 = "TestString_0443";
+    public static final String string_0444 = "TestString_0444";
+    public static final String string_0445 = "TestString_0445";
+    public static final String string_0446 = "TestString_0446";
+    public static final String string_0447 = "TestString_0447";
+    public static final String string_0448 = "TestString_0448";
+    public static final String string_0449 = "TestString_0449";
+    public static final String string_0450 = "TestString_0450";
+    public static final String string_0451 = "TestString_0451";
+    public static final String string_0452 = "TestString_0452";
+    public static final String string_0453 = "TestString_0453";
+    public static final String string_0454 = "TestString_0454";
+    public static final String string_0455 = "TestString_0455";
+    public static final String string_0456 = "TestString_0456";
+    public static final String string_0457 = "TestString_0457";
+    public static final String string_0458 = "TestString_0458";
+    public static final String string_0459 = "TestString_0459";
+    public static final String string_0460 = "TestString_0460";
+    public static final String string_0461 = "TestString_0461";
+    public static final String string_0462 = "TestString_0462";
+    public static final String string_0463 = "TestString_0463";
+    public static final String string_0464 = "TestString_0464";
+    public static final String string_0465 = "TestString_0465";
+    public static final String string_0466 = "TestString_0466";
+    public static final String string_0467 = "TestString_0467";
+    public static final String string_0468 = "TestString_0468";
+    public static final String string_0469 = "TestString_0469";
+    public static final String string_0470 = "TestString_0470";
+    public static final String string_0471 = "TestString_0471";
+    public static final String string_0472 = "TestString_0472";
+    public static final String string_0473 = "TestString_0473";
+    public static final String string_0474 = "TestString_0474";
+    public static final String string_0475 = "TestString_0475";
+    public static final String string_0476 = "TestString_0476";
+    public static final String string_0477 = "TestString_0477";
+    public static final String string_0478 = "TestString_0478";
+    public static final String string_0479 = "TestString_0479";
+    public static final String string_0480 = "TestString_0480";
+    public static final String string_0481 = "TestString_0481";
+    public static final String string_0482 = "TestString_0482";
+    public static final String string_0483 = "TestString_0483";
+    public static final String string_0484 = "TestString_0484";
+    public static final String string_0485 = "TestString_0485";
+    public static final String string_0486 = "TestString_0486";
+    public static final String string_0487 = "TestString_0487";
+    public static final String string_0488 = "TestString_0488";
+    public static final String string_0489 = "TestString_0489";
+    public static final String string_0490 = "TestString_0490";
+    public static final String string_0491 = "TestString_0491";
+    public static final String string_0492 = "TestString_0492";
+    public static final String string_0493 = "TestString_0493";
+    public static final String string_0494 = "TestString_0494";
+    public static final String string_0495 = "TestString_0495";
+    public static final String string_0496 = "TestString_0496";
+    public static final String string_0497 = "TestString_0497";
+    public static final String string_0498 = "TestString_0498";
+    public static final String string_0499 = "TestString_0499";
+    public static final String string_0500 = "TestString_0500";
+    public static final String string_0501 = "TestString_0501";
+    public static final String string_0502 = "TestString_0502";
+    public static final String string_0503 = "TestString_0503";
+    public static final String string_0504 = "TestString_0504";
+    public static final String string_0505 = "TestString_0505";
+    public static final String string_0506 = "TestString_0506";
+    public static final String string_0507 = "TestString_0507";
+    public static final String string_0508 = "TestString_0508";
+    public static final String string_0509 = "TestString_0509";
+    public static final String string_0510 = "TestString_0510";
+    public static final String string_0511 = "TestString_0511";
+    public static final String string_0512 = "TestString_0512";
+    public static final String string_0513 = "TestString_0513";
+    public static final String string_0514 = "TestString_0514";
+    public static final String string_0515 = "TestString_0515";
+    public static final String string_0516 = "TestString_0516";
+    public static final String string_0517 = "TestString_0517";
+    public static final String string_0518 = "TestString_0518";
+    public static final String string_0519 = "TestString_0519";
+    public static final String string_0520 = "TestString_0520";
+    public static final String string_0521 = "TestString_0521";
+    public static final String string_0522 = "TestString_0522";
+    public static final String string_0523 = "TestString_0523";
+    public static final String string_0524 = "TestString_0524";
+    public static final String string_0525 = "TestString_0525";
+    public static final String string_0526 = "TestString_0526";
+    public static final String string_0527 = "TestString_0527";
+    public static final String string_0528 = "TestString_0528";
+    public static final String string_0529 = "TestString_0529";
+    public static final String string_0530 = "TestString_0530";
+    public static final String string_0531 = "TestString_0531";
+    public static final String string_0532 = "TestString_0532";
+    public static final String string_0533 = "TestString_0533";
+    public static final String string_0534 = "TestString_0534";
+    public static final String string_0535 = "TestString_0535";
+    public static final String string_0536 = "TestString_0536";
+    public static final String string_0537 = "TestString_0537";
+    public static final String string_0538 = "TestString_0538";
+    public static final String string_0539 = "TestString_0539";
+    public static final String string_0540 = "TestString_0540";
+    public static final String string_0541 = "TestString_0541";
+    public static final String string_0542 = "TestString_0542";
+    public static final String string_0543 = "TestString_0543";
+    public static final String string_0544 = "TestString_0544";
+    public static final String string_0545 = "TestString_0545";
+    public static final String string_0546 = "TestString_0546";
+    public static final String string_0547 = "TestString_0547";
+    public static final String string_0548 = "TestString_0548";
+    public static final String string_0549 = "TestString_0549";
+    public static final String string_0550 = "TestString_0550";
+    public static final String string_0551 = "TestString_0551";
+    public static final String string_0552 = "TestString_0552";
+    public static final String string_0553 = "TestString_0553";
+    public static final String string_0554 = "TestString_0554";
+    public static final String string_0555 = "TestString_0555";
+    public static final String string_0556 = "TestString_0556";
+    public static final String string_0557 = "TestString_0557";
+    public static final String string_0558 = "TestString_0558";
+    public static final String string_0559 = "TestString_0559";
+    public static final String string_0560 = "TestString_0560";
+    public static final String string_0561 = "TestString_0561";
+    public static final String string_0562 = "TestString_0562";
+    public static final String string_0563 = "TestString_0563";
+    public static final String string_0564 = "TestString_0564";
+    public static final String string_0565 = "TestString_0565";
+    public static final String string_0566 = "TestString_0566";
+    public static final String string_0567 = "TestString_0567";
+    public static final String string_0568 = "TestString_0568";
+    public static final String string_0569 = "TestString_0569";
+    public static final String string_0570 = "TestString_0570";
+    public static final String string_0571 = "TestString_0571";
+    public static final String string_0572 = "TestString_0572";
+    public static final String string_0573 = "TestString_0573";
+    public static final String string_0574 = "TestString_0574";
+    public static final String string_0575 = "TestString_0575";
+    public static final String string_0576 = "TestString_0576";
+    public static final String string_0577 = "TestString_0577";
+    public static final String string_0578 = "TestString_0578";
+    public static final String string_0579 = "TestString_0579";
+    public static final String string_0580 = "TestString_0580";
+    public static final String string_0581 = "TestString_0581";
+    public static final String string_0582 = "TestString_0582";
+    public static final String string_0583 = "TestString_0583";
+    public static final String string_0584 = "TestString_0584";
+    public static final String string_0585 = "TestString_0585";
+    public static final String string_0586 = "TestString_0586";
+    public static final String string_0587 = "TestString_0587";
+    public static final String string_0588 = "TestString_0588";
+    public static final String string_0589 = "TestString_0589";
+    public static final String string_0590 = "TestString_0590";
+    public static final String string_0591 = "TestString_0591";
+    public static final String string_0592 = "TestString_0592";
+    public static final String string_0593 = "TestString_0593";
+    public static final String string_0594 = "TestString_0594";
+    public static final String string_0595 = "TestString_0595";
+    public static final String string_0596 = "TestString_0596";
+    public static final String string_0597 = "TestString_0597";
+    public static final String string_0598 = "TestString_0598";
+    public static final String string_0599 = "TestString_0599";
+    public static final String string_0600 = "TestString_0600";
+    public static final String string_0601 = "TestString_0601";
+    public static final String string_0602 = "TestString_0602";
+    public static final String string_0603 = "TestString_0603";
+    public static final String string_0604 = "TestString_0604";
+    public static final String string_0605 = "TestString_0605";
+    public static final String string_0606 = "TestString_0606";
+    public static final String string_0607 = "TestString_0607";
+    public static final String string_0608 = "TestString_0608";
+    public static final String string_0609 = "TestString_0609";
+    public static final String string_0610 = "TestString_0610";
+    public static final String string_0611 = "TestString_0611";
+    public static final String string_0612 = "TestString_0612";
+    public static final String string_0613 = "TestString_0613";
+    public static final String string_0614 = "TestString_0614";
+    public static final String string_0615 = "TestString_0615";
+    public static final String string_0616 = "TestString_0616";
+    public static final String string_0617 = "TestString_0617";
+    public static final String string_0618 = "TestString_0618";
+    public static final String string_0619 = "TestString_0619";
+    public static final String string_0620 = "TestString_0620";
+    public static final String string_0621 = "TestString_0621";
+    public static final String string_0622 = "TestString_0622";
+    public static final String string_0623 = "TestString_0623";
+    public static final String string_0624 = "TestString_0624";
+    public static final String string_0625 = "TestString_0625";
+    public static final String string_0626 = "TestString_0626";
+    public static final String string_0627 = "TestString_0627";
+    public static final String string_0628 = "TestString_0628";
+    public static final String string_0629 = "TestString_0629";
+    public static final String string_0630 = "TestString_0630";
+    public static final String string_0631 = "TestString_0631";
+    public static final String string_0632 = "TestString_0632";
+    public static final String string_0633 = "TestString_0633";
+    public static final String string_0634 = "TestString_0634";
+    public static final String string_0635 = "TestString_0635";
+    public static final String string_0636 = "TestString_0636";
+    public static final String string_0637 = "TestString_0637";
+    public static final String string_0638 = "TestString_0638";
+    public static final String string_0639 = "TestString_0639";
+    public static final String string_0640 = "TestString_0640";
+    public static final String string_0641 = "TestString_0641";
+    public static final String string_0642 = "TestString_0642";
+    public static final String string_0643 = "TestString_0643";
+    public static final String string_0644 = "TestString_0644";
+    public static final String string_0645 = "TestString_0645";
+    public static final String string_0646 = "TestString_0646";
+    public static final String string_0647 = "TestString_0647";
+    public static final String string_0648 = "TestString_0648";
+    public static final String string_0649 = "TestString_0649";
+    public static final String string_0650 = "TestString_0650";
+    public static final String string_0651 = "TestString_0651";
+    public static final String string_0652 = "TestString_0652";
+    public static final String string_0653 = "TestString_0653";
+    public static final String string_0654 = "TestString_0654";
+    public static final String string_0655 = "TestString_0655";
+    public static final String string_0656 = "TestString_0656";
+    public static final String string_0657 = "TestString_0657";
+    public static final String string_0658 = "TestString_0658";
+    public static final String string_0659 = "TestString_0659";
+    public static final String string_0660 = "TestString_0660";
+    public static final String string_0661 = "TestString_0661";
+    public static final String string_0662 = "TestString_0662";
+    public static final String string_0663 = "TestString_0663";
+    public static final String string_0664 = "TestString_0664";
+    public static final String string_0665 = "TestString_0665";
+    public static final String string_0666 = "TestString_0666";
+    public static final String string_0667 = "TestString_0667";
+    public static final String string_0668 = "TestString_0668";
+    public static final String string_0669 = "TestString_0669";
+    public static final String string_0670 = "TestString_0670";
+    public static final String string_0671 = "TestString_0671";
+    public static final String string_0672 = "TestString_0672";
+    public static final String string_0673 = "TestString_0673";
+    public static final String string_0674 = "TestString_0674";
+    public static final String string_0675 = "TestString_0675";
+    public static final String string_0676 = "TestString_0676";
+    public static final String string_0677 = "TestString_0677";
+    public static final String string_0678 = "TestString_0678";
+    public static final String string_0679 = "TestString_0679";
+    public static final String string_0680 = "TestString_0680";
+    public static final String string_0681 = "TestString_0681";
+    public static final String string_0682 = "TestString_0682";
+    public static final String string_0683 = "TestString_0683";
+    public static final String string_0684 = "TestString_0684";
+    public static final String string_0685 = "TestString_0685";
+    public static final String string_0686 = "TestString_0686";
+    public static final String string_0687 = "TestString_0687";
+    public static final String string_0688 = "TestString_0688";
+    public static final String string_0689 = "TestString_0689";
+    public static final String string_0690 = "TestString_0690";
+    public static final String string_0691 = "TestString_0691";
+    public static final String string_0692 = "TestString_0692";
+    public static final String string_0693 = "TestString_0693";
+    public static final String string_0694 = "TestString_0694";
+    public static final String string_0695 = "TestString_0695";
+    public static final String string_0696 = "TestString_0696";
+    public static final String string_0697 = "TestString_0697";
+    public static final String string_0698 = "TestString_0698";
+    public static final String string_0699 = "TestString_0699";
+    public static final String string_0700 = "TestString_0700";
+    public static final String string_0701 = "TestString_0701";
+    public static final String string_0702 = "TestString_0702";
+    public static final String string_0703 = "TestString_0703";
+    public static final String string_0704 = "TestString_0704";
+    public static final String string_0705 = "TestString_0705";
+    public static final String string_0706 = "TestString_0706";
+    public static final String string_0707 = "TestString_0707";
+    public static final String string_0708 = "TestString_0708";
+    public static final String string_0709 = "TestString_0709";
+    public static final String string_0710 = "TestString_0710";
+    public static final String string_0711 = "TestString_0711";
+    public static final String string_0712 = "TestString_0712";
+    public static final String string_0713 = "TestString_0713";
+    public static final String string_0714 = "TestString_0714";
+    public static final String string_0715 = "TestString_0715";
+    public static final String string_0716 = "TestString_0716";
+    public static final String string_0717 = "TestString_0717";
+    public static final String string_0718 = "TestString_0718";
+    public static final String string_0719 = "TestString_0719";
+    public static final String string_0720 = "TestString_0720";
+    public static final String string_0721 = "TestString_0721";
+    public static final String string_0722 = "TestString_0722";
+    public static final String string_0723 = "TestString_0723";
+    public static final String string_0724 = "TestString_0724";
+    public static final String string_0725 = "TestString_0725";
+    public static final String string_0726 = "TestString_0726";
+    public static final String string_0727 = "TestString_0727";
+    public static final String string_0728 = "TestString_0728";
+    public static final String string_0729 = "TestString_0729";
+    public static final String string_0730 = "TestString_0730";
+    public static final String string_0731 = "TestString_0731";
+    public static final String string_0732 = "TestString_0732";
+    public static final String string_0733 = "TestString_0733";
+    public static final String string_0734 = "TestString_0734";
+    public static final String string_0735 = "TestString_0735";
+    public static final String string_0736 = "TestString_0736";
+    public static final String string_0737 = "TestString_0737";
+    public static final String string_0738 = "TestString_0738";
+    public static final String string_0739 = "TestString_0739";
+    public static final String string_0740 = "TestString_0740";
+    public static final String string_0741 = "TestString_0741";
+    public static final String string_0742 = "TestString_0742";
+    public static final String string_0743 = "TestString_0743";
+    public static final String string_0744 = "TestString_0744";
+    public static final String string_0745 = "TestString_0745";
+    public static final String string_0746 = "TestString_0746";
+    public static final String string_0747 = "TestString_0747";
+    public static final String string_0748 = "TestString_0748";
+    public static final String string_0749 = "TestString_0749";
+    public static final String string_0750 = "TestString_0750";
+    public static final String string_0751 = "TestString_0751";
+    public static final String string_0752 = "TestString_0752";
+    public static final String string_0753 = "TestString_0753";
+    public static final String string_0754 = "TestString_0754";
+    public static final String string_0755 = "TestString_0755";
+    public static final String string_0756 = "TestString_0756";
+    public static final String string_0757 = "TestString_0757";
+    public static final String string_0758 = "TestString_0758";
+    public static final String string_0759 = "TestString_0759";
+    public static final String string_0760 = "TestString_0760";
+    public static final String string_0761 = "TestString_0761";
+    public static final String string_0762 = "TestString_0762";
+    public static final String string_0763 = "TestString_0763";
+    public static final String string_0764 = "TestString_0764";
+    public static final String string_0765 = "TestString_0765";
+    public static final String string_0766 = "TestString_0766";
+    public static final String string_0767 = "TestString_0767";
+    public static final String string_0768 = "TestString_0768";
+    public static final String string_0769 = "TestString_0769";
+    public static final String string_0770 = "TestString_0770";
+    public static final String string_0771 = "TestString_0771";
+    public static final String string_0772 = "TestString_0772";
+    public static final String string_0773 = "TestString_0773";
+    public static final String string_0774 = "TestString_0774";
+    public static final String string_0775 = "TestString_0775";
+    public static final String string_0776 = "TestString_0776";
+    public static final String string_0777 = "TestString_0777";
+    public static final String string_0778 = "TestString_0778";
+    public static final String string_0779 = "TestString_0779";
+    public static final String string_0780 = "TestString_0780";
+    public static final String string_0781 = "TestString_0781";
+    public static final String string_0782 = "TestString_0782";
+    public static final String string_0783 = "TestString_0783";
+    public static final String string_0784 = "TestString_0784";
+    public static final String string_0785 = "TestString_0785";
+    public static final String string_0786 = "TestString_0786";
+    public static final String string_0787 = "TestString_0787";
+    public static final String string_0788 = "TestString_0788";
+    public static final String string_0789 = "TestString_0789";
+    public static final String string_0790 = "TestString_0790";
+    public static final String string_0791 = "TestString_0791";
+    public static final String string_0792 = "TestString_0792";
+    public static final String string_0793 = "TestString_0793";
+    public static final String string_0794 = "TestString_0794";
+    public static final String string_0795 = "TestString_0795";
+    public static final String string_0796 = "TestString_0796";
+    public static final String string_0797 = "TestString_0797";
+    public static final String string_0798 = "TestString_0798";
+    public static final String string_0799 = "TestString_0799";
+    public static final String string_0800 = "TestString_0800";
+    public static final String string_0801 = "TestString_0801";
+    public static final String string_0802 = "TestString_0802";
+    public static final String string_0803 = "TestString_0803";
+    public static final String string_0804 = "TestString_0804";
+    public static final String string_0805 = "TestString_0805";
+    public static final String string_0806 = "TestString_0806";
+    public static final String string_0807 = "TestString_0807";
+    public static final String string_0808 = "TestString_0808";
+    public static final String string_0809 = "TestString_0809";
+    public static final String string_0810 = "TestString_0810";
+    public static final String string_0811 = "TestString_0811";
+    public static final String string_0812 = "TestString_0812";
+    public static final String string_0813 = "TestString_0813";
+    public static final String string_0814 = "TestString_0814";
+    public static final String string_0815 = "TestString_0815";
+    public static final String string_0816 = "TestString_0816";
+    public static final String string_0817 = "TestString_0817";
+    public static final String string_0818 = "TestString_0818";
+    public static final String string_0819 = "TestString_0819";
+    public static final String string_0820 = "TestString_0820";
+    public static final String string_0821 = "TestString_0821";
+    public static final String string_0822 = "TestString_0822";
+    public static final String string_0823 = "TestString_0823";
+    public static final String string_0824 = "TestString_0824";
+    public static final String string_0825 = "TestString_0825";
+    public static final String string_0826 = "TestString_0826";
+    public static final String string_0827 = "TestString_0827";
+    public static final String string_0828 = "TestString_0828";
+    public static final String string_0829 = "TestString_0829";
+    public static final String string_0830 = "TestString_0830";
+    public static final String string_0831 = "TestString_0831";
+    public static final String string_0832 = "TestString_0832";
+    public static final String string_0833 = "TestString_0833";
+    public static final String string_0834 = "TestString_0834";
+    public static final String string_0835 = "TestString_0835";
+    public static final String string_0836 = "TestString_0836";
+    public static final String string_0837 = "TestString_0837";
+    public static final String string_0838 = "TestString_0838";
+    public static final String string_0839 = "TestString_0839";
+    public static final String string_0840 = "TestString_0840";
+    public static final String string_0841 = "TestString_0841";
+    public static final String string_0842 = "TestString_0842";
+    public static final String string_0843 = "TestString_0843";
+    public static final String string_0844 = "TestString_0844";
+    public static final String string_0845 = "TestString_0845";
+    public static final String string_0846 = "TestString_0846";
+    public static final String string_0847 = "TestString_0847";
+    public static final String string_0848 = "TestString_0848";
+    public static final String string_0849 = "TestString_0849";
+    public static final String string_0850 = "TestString_0850";
+    public static final String string_0851 = "TestString_0851";
+    public static final String string_0852 = "TestString_0852";
+    public static final String string_0853 = "TestString_0853";
+    public static final String string_0854 = "TestString_0854";
+    public static final String string_0855 = "TestString_0855";
+    public static final String string_0856 = "TestString_0856";
+    public static final String string_0857 = "TestString_0857";
+    public static final String string_0858 = "TestString_0858";
+    public static final String string_0859 = "TestString_0859";
+    public static final String string_0860 = "TestString_0860";
+    public static final String string_0861 = "TestString_0861";
+    public static final String string_0862 = "TestString_0862";
+    public static final String string_0863 = "TestString_0863";
+    public static final String string_0864 = "TestString_0864";
+    public static final String string_0865 = "TestString_0865";
+    public static final String string_0866 = "TestString_0866";
+    public static final String string_0867 = "TestString_0867";
+    public static final String string_0868 = "TestString_0868";
+    public static final String string_0869 = "TestString_0869";
+    public static final String string_0870 = "TestString_0870";
+    public static final String string_0871 = "TestString_0871";
+    public static final String string_0872 = "TestString_0872";
+    public static final String string_0873 = "TestString_0873";
+    public static final String string_0874 = "TestString_0874";
+    public static final String string_0875 = "TestString_0875";
+    public static final String string_0876 = "TestString_0876";
+    public static final String string_0877 = "TestString_0877";
+    public static final String string_0878 = "TestString_0878";
+    public static final String string_0879 = "TestString_0879";
+    public static final String string_0880 = "TestString_0880";
+    public static final String string_0881 = "TestString_0881";
+    public static final String string_0882 = "TestString_0882";
+    public static final String string_0883 = "TestString_0883";
+    public static final String string_0884 = "TestString_0884";
+    public static final String string_0885 = "TestString_0885";
+    public static final String string_0886 = "TestString_0886";
+    public static final String string_0887 = "TestString_0887";
+    public static final String string_0888 = "TestString_0888";
+    public static final String string_0889 = "TestString_0889";
+    public static final String string_0890 = "TestString_0890";
+    public static final String string_0891 = "TestString_0891";
+    public static final String string_0892 = "TestString_0892";
+    public static final String string_0893 = "TestString_0893";
+    public static final String string_0894 = "TestString_0894";
+    public static final String string_0895 = "TestString_0895";
+    public static final String string_0896 = "TestString_0896";
+    public static final String string_0897 = "TestString_0897";
+    public static final String string_0898 = "TestString_0898";
+    public static final String string_0899 = "TestString_0899";
+    public static final String string_0900 = "TestString_0900";
+    public static final String string_0901 = "TestString_0901";
+    public static final String string_0902 = "TestString_0902";
+    public static final String string_0903 = "TestString_0903";
+    public static final String string_0904 = "TestString_0904";
+    public static final String string_0905 = "TestString_0905";
+    public static final String string_0906 = "TestString_0906";
+    public static final String string_0907 = "TestString_0907";
+    public static final String string_0908 = "TestString_0908";
+    public static final String string_0909 = "TestString_0909";
+    public static final String string_0910 = "TestString_0910";
+    public static final String string_0911 = "TestString_0911";
+    public static final String string_0912 = "TestString_0912";
+    public static final String string_0913 = "TestString_0913";
+    public static final String string_0914 = "TestString_0914";
+    public static final String string_0915 = "TestString_0915";
+    public static final String string_0916 = "TestString_0916";
+    public static final String string_0917 = "TestString_0917";
+    public static final String string_0918 = "TestString_0918";
+    public static final String string_0919 = "TestString_0919";
+    public static final String string_0920 = "TestString_0920";
+    public static final String string_0921 = "TestString_0921";
+    public static final String string_0922 = "TestString_0922";
+    public static final String string_0923 = "TestString_0923";
+    public static final String string_0924 = "TestString_0924";
+    public static final String string_0925 = "TestString_0925";
+    public static final String string_0926 = "TestString_0926";
+    public static final String string_0927 = "TestString_0927";
+    public static final String string_0928 = "TestString_0928";
+    public static final String string_0929 = "TestString_0929";
+    public static final String string_0930 = "TestString_0930";
+    public static final String string_0931 = "TestString_0931";
+    public static final String string_0932 = "TestString_0932";
+    public static final String string_0933 = "TestString_0933";
+    public static final String string_0934 = "TestString_0934";
+    public static final String string_0935 = "TestString_0935";
+    public static final String string_0936 = "TestString_0936";
+    public static final String string_0937 = "TestString_0937";
+    public static final String string_0938 = "TestString_0938";
+    public static final String string_0939 = "TestString_0939";
+    public static final String string_0940 = "TestString_0940";
+    public static final String string_0941 = "TestString_0941";
+    public static final String string_0942 = "TestString_0942";
+    public static final String string_0943 = "TestString_0943";
+    public static final String string_0944 = "TestString_0944";
+    public static final String string_0945 = "TestString_0945";
+    public static final String string_0946 = "TestString_0946";
+    public static final String string_0947 = "TestString_0947";
+    public static final String string_0948 = "TestString_0948";
+    public static final String string_0949 = "TestString_0949";
+    public static final String string_0950 = "TestString_0950";
+    public static final String string_0951 = "TestString_0951";
+    public static final String string_0952 = "TestString_0952";
+    public static final String string_0953 = "TestString_0953";
+    public static final String string_0954 = "TestString_0954";
+    public static final String string_0955 = "TestString_0955";
+    public static final String string_0956 = "TestString_0956";
+    public static final String string_0957 = "TestString_0957";
+    public static final String string_0958 = "TestString_0958";
+    public static final String string_0959 = "TestString_0959";
+    public static final String string_0960 = "TestString_0960";
+    public static final String string_0961 = "TestString_0961";
+    public static final String string_0962 = "TestString_0962";
+    public static final String string_0963 = "TestString_0963";
+    public static final String string_0964 = "TestString_0964";
+    public static final String string_0965 = "TestString_0965";
+    public static final String string_0966 = "TestString_0966";
+    public static final String string_0967 = "TestString_0967";
+    public static final String string_0968 = "TestString_0968";
+    public static final String string_0969 = "TestString_0969";
+    public static final String string_0970 = "TestString_0970";
+    public static final String string_0971 = "TestString_0971";
+    public static final String string_0972 = "TestString_0972";
+    public static final String string_0973 = "TestString_0973";
+    public static final String string_0974 = "TestString_0974";
+    public static final String string_0975 = "TestString_0975";
+    public static final String string_0976 = "TestString_0976";
+    public static final String string_0977 = "TestString_0977";
+    public static final String string_0978 = "TestString_0978";
+    public static final String string_0979 = "TestString_0979";
+    public static final String string_0980 = "TestString_0980";
+    public static final String string_0981 = "TestString_0981";
+    public static final String string_0982 = "TestString_0982";
+    public static final String string_0983 = "TestString_0983";
+    public static final String string_0984 = "TestString_0984";
+    public static final String string_0985 = "TestString_0985";
+    public static final String string_0986 = "TestString_0986";
+    public static final String string_0987 = "TestString_0987";
+    public static final String string_0988 = "TestString_0988";
+    public static final String string_0989 = "TestString_0989";
+    public static final String string_0990 = "TestString_0990";
+    public static final String string_0991 = "TestString_0991";
+    public static final String string_0992 = "TestString_0992";
+    public static final String string_0993 = "TestString_0993";
+    public static final String string_0994 = "TestString_0994";
+    public static final String string_0995 = "TestString_0995";
+    public static final String string_0996 = "TestString_0996";
+    public static final String string_0997 = "TestString_0997";
+    public static final String string_0998 = "TestString_0998";
+    public static final String string_0999 = "TestString_0999";
+    public static final String string_1000 = "TestString_1000";
+    public static final String string_1001 = "TestString_1001";
+    public static final String string_1002 = "TestString_1002";
+    public static final String string_1003 = "TestString_1003";
+    public static final String string_1004 = "TestString_1004";
+    public static final String string_1005 = "TestString_1005";
+    public static final String string_1006 = "TestString_1006";
+    public static final String string_1007 = "TestString_1007";
+    public static final String string_1008 = "TestString_1008";
+    public static final String string_1009 = "TestString_1009";
+    public static final String string_1010 = "TestString_1010";
+    public static final String string_1011 = "TestString_1011";
+    public static final String string_1012 = "TestString_1012";
+    public static final String string_1013 = "TestString_1013";
+    public static final String string_1014 = "TestString_1014";
+    public static final String string_1015 = "TestString_1015";
+    public static final String string_1016 = "TestString_1016";
+    public static final String string_1017 = "TestString_1017";
+    public static final String string_1018 = "TestString_1018";
+    public static final String string_1019 = "TestString_1019";
+    public static final String string_1020 = "TestString_1020";
+    public static final String string_1021 = "TestString_1021";
+    public static final String string_1022 = "TestString_1022";
+    public static final String string_1023 = "TestString_1023";
+    public static final String string_1024 = "TestString_1024";
+
+    public void timeConstStringsWithConflict(int count) {
+      for (int i = 0; i < count; ++i) {
+        $noinline$foo("TestString_0000");
+        $noinline$foo("TestString_1024");
+      }
+    }
+
+    public void timeConstStringsWithoutConflict(int count) {
+      for (int i = 0; i < count; ++i) {
+        $noinline$foo("TestString_0001");
+        $noinline$foo("TestString_1023");
+      }
+    }
+
+    static void $noinline$foo(String s) {
+      if (doThrow) { throw new Error(); }
+    }
+
+    public static boolean doThrow = false;
+}
diff --git a/benchmark/jni-perf/perf_jni.cc b/benchmark/jni-perf/perf_jni.cc
index cd8d520..06dded8 100644
--- a/benchmark/jni-perf/perf_jni.cc
+++ b/benchmark/jni-perf/perf_jni.cc
@@ -17,7 +17,7 @@
 #include <assert.h>
 
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/benchmark/jobject-benchmark/jobject_benchmark.cc b/benchmark/jobject-benchmark/jobject_benchmark.cc
index e7ca9eb..4b2c024 100644
--- a/benchmark/jobject-benchmark/jobject_benchmark.cc
+++ b/benchmark/jobject-benchmark/jobject_benchmark.cc
@@ -16,8 +16,9 @@
 
 #include "jni.h"
 
+#include "java_vm_ext.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace {
@@ -25,10 +26,10 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveLocal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
-    jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+    jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
     soa.Env()->DeleteLocalRef(ref);
   }
 }
@@ -36,11 +37,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeLocal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
-  jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+  jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Env()->DeleteLocalRef(ref);
 }
@@ -48,7 +49,7 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
     jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
@@ -59,11 +60,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Vm()->DeleteGlobalRef(soa.Self(), ref);
 }
@@ -71,7 +72,7 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveWeakGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
     jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
@@ -82,11 +83,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeWeakGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Vm()->DeleteWeakGlobalRef(soa.Self(), ref);
 }
@@ -95,7 +96,7 @@
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
   for (jint i = 0; i < reps; ++i) {
-    soa.Decode<mirror::Object*>(jobj);
+    soa.Decode<mirror::Object>(jobj);
   }
 }
 
diff --git a/build/art.go b/build/art.go
index 0ae6c8f..b826538 100644
--- a/build/art.go
+++ b/build/art.go
@@ -91,7 +91,7 @@
 	var cflags []string
 	deviceFrameSizeLimit := 1736
 	if len(ctx.AConfig().SanitizeDevice()) > 0 {
-		deviceFrameSizeLimit = 6400
+		deviceFrameSizeLimit = 7400
 	}
 	cflags = append(cflags,
 		fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
diff --git a/compiler/Android.bp b/compiler/Android.bp
index f264d30..7fb009a 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -31,8 +31,6 @@
         "dex/verified_method.cc",
         "dex/verification_results.cc",
         "dex/quick_compiler_callbacks.cc",
-        "dex/quick/dex_file_method_inliner.cc",
-        "dex/quick/dex_file_to_method_inliner_map.cc",
         "driver/compiled_method_storage.cc",
         "driver/compiler_driver.cc",
         "driver/compiler_options.cc",
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 2af4d72..b726649 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -23,7 +23,6 @@
 #include "class_linker.h"
 #include "compiled_method.h"
 #include "dex/quick_compiler_callbacks.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
@@ -33,7 +32,7 @@
 #include "mirror/dex_cache.h"
 #include "mirror/object-inl.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
@@ -109,7 +108,8 @@
   FlushInstructionCache(reinterpret_cast<char*>(base), reinterpret_cast<char*>(base + len));
 }
 
-void CommonCompilerTest::MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name) {
+void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader,
+                                        const char* class_name) {
   std::string class_descriptor(DotToDescriptor(class_name));
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
@@ -176,7 +176,6 @@
                                               size_t number_of_threads) {
   compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                             verification_results_.get(),
-                                            method_inliner_map_.get(),
                                             kind,
                                             isa,
                                             instruction_set_features_.get(),
@@ -200,9 +199,7 @@
 
   compiler_options_.reset(new CompilerOptions);
   verification_results_.reset(new VerificationResults(compiler_options_.get()));
-  method_inliner_map_.reset(new DexFileToMethodInlinerMap);
   callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
-                                              method_inliner_map_.get(),
                                               CompilerCallbacks::CallbackMode::kCompileApp));
 }
 
@@ -223,7 +220,6 @@
   timer_.reset();
   compiler_driver_.reset();
   callbacks_.reset();
-  method_inliner_map_.reset();
   verification_results_.reset();
   compiler_options_.reset();
   image_reservation_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 5239121..f4838c1 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -34,7 +34,6 @@
 class CompilerDriver;
 class CompilerOptions;
 class CumulativeLogger;
-class DexFileToMethodInlinerMap;
 class VerificationResults;
 
 template<class T> class Handle;
@@ -51,7 +50,7 @@
 
   static void MakeExecutable(const void* code_start, size_t code_length);
 
-  void MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name)
+  void MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader, const char* class_name)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  protected:
@@ -102,7 +101,6 @@
   Compiler::Kind compiler_kind_ = Compiler::kOptimizing;
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<VerificationResults> verification_results_;
-  std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
   std::unique_ptr<CumulativeLogger> timer_;
   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index e0abf19..236a3b2 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -280,7 +280,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(unit_.GetClassLoader())));
 
   ClassLinker* class_linker = unit_.GetClassLinker();
   ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
deleted file mode 100644
index 6750554..0000000
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include "dex_file_method_inliner.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/mutex-inl.h"
-#include "driver/compiler_driver.h"
-#include "thread-inl.h"
-#include "dex_instruction-inl.h"
-#include "driver/dex_compilation_unit.h"
-#include "verifier/method_verifier-inl.h"
-
-namespace art {
-
-namespace {  // anonymous namespace
-
-static constexpr bool kIntrinsicIsStatic[] = {
-    true,   // kIntrinsicDoubleCvt
-    true,   // kIntrinsicFloatCvt
-    true,   // kIntrinsicFloat2Int
-    true,   // kIntrinsicDouble2Long
-    true,   // kIntrinsicFloatIsInfinite
-    true,   // kIntrinsicDoubleIsInfinite
-    true,   // kIntrinsicFloatIsNaN
-    true,   // kIntrinsicDoubleIsNaN
-    true,   // kIntrinsicReverseBits
-    true,   // kIntrinsicReverseBytes
-    true,   // kIntrinsicBitCount
-    true,   // kIntrinsicCompare,
-    true,   // kIntrinsicHighestOneBit
-    true,   // kIntrinsicLowestOneBit
-    true,   // kIntrinsicNumberOfLeadingZeros
-    true,   // kIntrinsicNumberOfTrailingZeros
-    true,   // kIntrinsicRotateRight
-    true,   // kIntrinsicRotateLeft
-    true,   // kIntrinsicSignum
-    true,   // kIntrinsicAbsInt
-    true,   // kIntrinsicAbsLong
-    true,   // kIntrinsicAbsFloat
-    true,   // kIntrinsicAbsDouble
-    true,   // kIntrinsicMinMaxInt
-    true,   // kIntrinsicMinMaxLong
-    true,   // kIntrinsicMinMaxFloat
-    true,   // kIntrinsicMinMaxDouble
-    true,   // kIntrinsicCos
-    true,   // kIntrinsicSin
-    true,   // kIntrinsicAcos
-    true,   // kIntrinsicAsin
-    true,   // kIntrinsicAtan
-    true,   // kIntrinsicAtan2
-    true,   // kIntrinsicCbrt
-    true,   // kIntrinsicCosh
-    true,   // kIntrinsicExp
-    true,   // kIntrinsicExpm1
-    true,   // kIntrinsicHypot
-    true,   // kIntrinsicLog
-    true,   // kIntrinsicLog10
-    true,   // kIntrinsicNextAfter
-    true,   // kIntrinsicSinh
-    true,   // kIntrinsicTan
-    true,   // kIntrinsicTanh
-    true,   // kIntrinsicSqrt
-    true,   // kIntrinsicCeil
-    true,   // kIntrinsicFloor
-    true,   // kIntrinsicRint
-    true,   // kIntrinsicRoundFloat
-    true,   // kIntrinsicRoundDouble
-    false,  // kIntrinsicReferenceGetReferent
-    false,  // kIntrinsicCharAt
-    false,  // kIntrinsicCompareTo
-    false,  // kIntrinsicEquals
-    false,  // kIntrinsicGetCharsNoCheck
-    false,  // kIntrinsicIsEmptyOrLength
-    false,  // kIntrinsicIndexOf
-    true,   // kIntrinsicNewStringFromBytes
-    true,   // kIntrinsicNewStringFromChars
-    true,   // kIntrinsicNewStringFromString
-    true,   // kIntrinsicCurrentThread
-    true,   // kIntrinsicPeek
-    true,   // kIntrinsicPoke
-    false,  // kIntrinsicCas
-    false,  // kIntrinsicUnsafeGet
-    false,  // kIntrinsicUnsafePut
-    false,  // kIntrinsicUnsafeGetAndAddInt,
-    false,  // kIntrinsicUnsafeGetAndAddLong,
-    false,  // kIntrinsicUnsafeGetAndSetInt,
-    false,  // kIntrinsicUnsafeGetAndSetLong,
-    false,  // kIntrinsicUnsafeGetAndSetObject,
-    false,  // kIntrinsicUnsafeLoadFence,
-    false,  // kIntrinsicUnsafeStoreFence,
-    false,  // kIntrinsicUnsafeFullFence,
-    true,   // kIntrinsicSystemArrayCopyCharArray
-    true,   // kIntrinsicSystemArrayCopy
-};
-static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop,
-              "arraysize of kIntrinsicIsStatic unexpected");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloat2Int], "Float2Int must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDouble2Long], "Double2Long must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsInfinite], "FloatIsInfinite must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsInfinite], "DoubleIsInfinite must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsNaN], "FloatIsNaN must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsNaN], "DoubleIsNaN must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicBitCount], "BitCount must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCompare], "Compare must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicHighestOneBit], "HighestOneBit must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLowestOneBit], "LowestOneBit  must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros],
-              "NumberOfLeadingZeros must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros],
-              "NumberOfTrailingZeros must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSignum], "Signum must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCos], "Cos must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSin], "Sin must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAcos], "Acos must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAsin], "Asin must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAtan], "Atan must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAtan2], "Atan2 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCbrt], "Cbrt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCosh], "Cosh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicExp], "Exp must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicExpm1], "Expm1 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicHypot], "Hypot must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLog], "Log must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLog10], "Log10 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNextAfter], "NextAfter must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSinh], "Sinh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicTan], "Tan must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicTanh], "Tanh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicEquals], "String equals must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicGetCharsNoCheck], "GetCharsNoCheck must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromBytes],
-              "NewStringFromBytes must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromChars],
-              "NewStringFromChars must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromString],
-              "NewStringFromString must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddInt], "UnsafeGetAndAddInt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddLong], "UnsafeGetAndAddLong must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetInt], "UnsafeGetAndSetInt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetLong], "UnsafeGetAndSetLong must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetObject], "UnsafeGetAndSetObject must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeLoadFence], "UnsafeLoadFence must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeStoreFence], "UnsafeStoreFence must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeFullFence], "UnsafeFullFence must not be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray],
-              "SystemArrayCopyCharArray must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopy],
-              "SystemArrayCopy must be static");
-
-}  // anonymous namespace
-
-const uint32_t DexFileMethodInliner::kIndexUnresolved;
-const char* const DexFileMethodInliner::kClassCacheNames[] = {
-    "Z",                       // kClassCacheBoolean
-    "B",                       // kClassCacheByte
-    "C",                       // kClassCacheChar
-    "S",                       // kClassCacheShort
-    "I",                       // kClassCacheInt
-    "J",                       // kClassCacheLong
-    "F",                       // kClassCacheFloat
-    "D",                       // kClassCacheDouble
-    "V",                       // kClassCacheVoid
-    "[B",                      // kClassCacheJavaLangByteArray
-    "[C",                      // kClassCacheJavaLangCharArray
-    "[I",                      // kClassCacheJavaLangIntArray
-    "Ljava/lang/Object;",      // kClassCacheJavaLangObject
-    "Ljava/lang/ref/Reference;",   // kClassCacheJavaLangRefReference
-    "Ljava/lang/String;",      // kClassCacheJavaLangString
-    "Ljava/lang/StringBuffer;",    // kClassCacheJavaLangStringBuffer
-    "Ljava/lang/StringBuilder;",   // kClassCacheJavaLangStringBuilder
-    "Ljava/lang/StringFactory;",   // kClassCacheJavaLangStringFactory
-    "Ljava/lang/Double;",      // kClassCacheJavaLangDouble
-    "Ljava/lang/Float;",       // kClassCacheJavaLangFloat
-    "Ljava/lang/Integer;",     // kClassCacheJavaLangInteger
-    "Ljava/lang/Long;",        // kClassCacheJavaLangLong
-    "Ljava/lang/Short;",       // kClassCacheJavaLangShort
-    "Ljava/lang/Math;",        // kClassCacheJavaLangMath
-    "Ljava/lang/StrictMath;",  // kClassCacheJavaLangStrictMath
-    "Ljava/lang/Thread;",      // kClassCacheJavaLangThread
-    "Ljava/nio/charset/Charset;",  // kClassCacheJavaNioCharsetCharset
-    "Llibcore/io/Memory;",     // kClassCacheLibcoreIoMemory
-    "Lsun/misc/Unsafe;",       // kClassCacheSunMiscUnsafe
-    "Ljava/lang/System;",      // kClassCacheJavaLangSystem
-};
-
-const char* const DexFileMethodInliner::kNameCacheNames[] = {
-    "reverse",               // kNameCacheReverse
-    "reverseBytes",          // kNameCacheReverseBytes
-    "doubleToRawLongBits",   // kNameCacheDoubleToRawLongBits
-    "longBitsToDouble",      // kNameCacheLongBitsToDouble
-    "floatToRawIntBits",     // kNameCacheFloatToRawIntBits
-    "intBitsToFloat",        // kNameCacheIntBitsToFloat
-    "abs",                   // kNameCacheAbs
-    "max",                   // kNameCacheMax
-    "min",                   // kNameCacheMin
-    "cos",                   // kNameCacheCos
-    "sin",                   // kNameCacheSin
-    "acos",                  // kNameCacheAcos
-    "asin",                  // kNameCacheAsin
-    "atan",                  // kNameCacheAtan
-    "atan2",                 // kNameCacheAtan2
-    "cbrt",                  // kNameCacheCbrt
-    "cosh",                  // kNameCacheCosh
-    "exp",                   // kNameCacheExp
-    "expm1",                 // kNameCacheExpm1
-    "hypot",                 // kNameCacheHypot
-    "log",                   // kNameCacheLog
-    "log10",                 // kNameCacheLog10
-    "nextAfter",             // kNameCacheNextAfter
-    "sinh",                  // kNameCacheSinh
-    "tan",                   // kNameCacheTan
-    "tanh",                  // kNameCacheTanh
-    "sqrt",                  // kNameCacheSqrt
-    "ceil",                  // kNameCacheCeil
-    "floor",                 // kNameCacheFloor
-    "rint",                  // kNameCacheRint
-    "round",                 // kNameCacheRound
-    "getReferent",           // kNameCacheReferenceGet
-    "charAt",                // kNameCacheCharAt
-    "compareTo",             // kNameCacheCompareTo
-    "equals",                // kNameCacheEquals
-    "getCharsNoCheck",       // kNameCacheGetCharsNoCheck
-    "isEmpty",               // kNameCacheIsEmpty
-    "floatToIntBits",        // kNameCacheFloatToIntBits
-    "doubleToLongBits",      // kNameCacheDoubleToLongBits
-    "isInfinite",            // kNameCacheIsInfinite
-    "isNaN",                 // kNameCacheIsNaN
-    "indexOf",               // kNameCacheIndexOf
-    "length",                // kNameCacheLength
-    "<init>",                // kNameCacheInit
-    "newStringFromBytes",    // kNameCacheNewStringFromBytes
-    "newStringFromChars",    // kNameCacheNewStringFromChars
-    "newStringFromString",   // kNameCacheNewStringFromString
-    "currentThread",         // kNameCacheCurrentThread
-    "peekByte",              // kNameCachePeekByte
-    "peekIntNative",         // kNameCachePeekIntNative
-    "peekLongNative",        // kNameCachePeekLongNative
-    "peekShortNative",       // kNameCachePeekShortNative
-    "pokeByte",              // kNameCachePokeByte
-    "pokeIntNative",         // kNameCachePokeIntNative
-    "pokeLongNative",        // kNameCachePokeLongNative
-    "pokeShortNative",       // kNameCachePokeShortNative
-    "compareAndSwapInt",     // kNameCacheCompareAndSwapInt
-    "compareAndSwapLong",    // kNameCacheCompareAndSwapLong
-    "compareAndSwapObject",  // kNameCacheCompareAndSwapObject
-    "getInt",                // kNameCacheGetInt
-    "getIntVolatile",        // kNameCacheGetIntVolatile
-    "putInt",                // kNameCachePutInt
-    "putIntVolatile",        // kNameCachePutIntVolatile
-    "putOrderedInt",         // kNameCachePutOrderedInt
-    "getLong",               // kNameCacheGetLong
-    "getLongVolatile",       // kNameCacheGetLongVolatile
-    "putLong",               // kNameCachePutLong
-    "putLongVolatile",       // kNameCachePutLongVolatile
-    "putOrderedLong",        // kNameCachePutOrderedLong
-    "getObject",             // kNameCacheGetObject
-    "getObjectVolatile",     // kNameCacheGetObjectVolatile
-    "putObject",             // kNameCachePutObject
-    "putObjectVolatile",     // kNameCachePutObjectVolatile
-    "putOrderedObject",      // kNameCachePutOrderedObject
-    "getAndAddInt",          // kNameCacheGetAndAddInt,
-    "getAndAddLong",         // kNameCacheGetAndAddLong,
-    "getAndSetInt",          // kNameCacheGetAndSetInt,
-    "getAndSetLong",         // kNameCacheGetAndSetLong,
-    "getAndSetObject",       // kNameCacheGetAndSetObject,
-    "loadFence",             // kNameCacheLoadFence,
-    "storeFence",            // kNameCacheStoreFence,
-    "fullFence",             // kNameCacheFullFence,
-    "arraycopy",             // kNameCacheArrayCopy
-    "bitCount",              // kNameCacheBitCount
-    "compare",               // kNameCacheCompare
-    "highestOneBit",         // kNameCacheHighestOneBit
-    "lowestOneBit",          // kNameCacheLowestOneBit
-    "numberOfLeadingZeros",  // kNameCacheNumberOfLeadingZeros
-    "numberOfTrailingZeros",  // kNameCacheNumberOfTrailingZeros
-    "rotateRight",           // kNameCacheRotateRight
-    "rotateLeft",            // kNameCacheRotateLeft
-    "signum",                // kNameCacheSignum
-};
-
-const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
-    // kProtoCacheI_I
-    { kClassCacheInt, 1, { kClassCacheInt } },
-    // kProtoCacheJ_J
-    { kClassCacheLong, 1, { kClassCacheLong } },
-    // kProtoCacheS_S
-    { kClassCacheShort, 1, { kClassCacheShort } },
-    // kProtoCacheD_D
-    { kClassCacheDouble, 1, { kClassCacheDouble } },
-    // kProtoCacheDD_D
-    { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } },
-    // kProtoCacheF_F
-    { kClassCacheFloat, 1, { kClassCacheFloat } },
-    // kProtoCacheFF_F
-    { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } },
-    // kProtoCacheD_J
-    { kClassCacheLong, 1, { kClassCacheDouble } },
-    // kProtoCacheD_Z
-    { kClassCacheBoolean, 1, { kClassCacheDouble } },
-    // kProtoCacheJ_D
-    { kClassCacheDouble, 1, { kClassCacheLong } },
-    // kProtoCacheF_I
-    { kClassCacheInt, 1, { kClassCacheFloat } },
-    // kProtoCacheF_Z
-    { kClassCacheBoolean, 1, { kClassCacheFloat } },
-    // kProtoCacheI_F
-    { kClassCacheFloat, 1, { kClassCacheInt } },
-    // kProtoCacheII_I
-    { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
-    // kProtoCacheI_C
-    { kClassCacheChar, 1, { kClassCacheInt } },
-    // kProtoCacheString_I
-    { kClassCacheInt, 1, { kClassCacheJavaLangString } },
-    // kProtoCache_Z
-    { kClassCacheBoolean, 0, { } },
-    // kProtoCache_I
-    { kClassCacheInt, 0, { } },
-    // kProtoCache_Object
-    { kClassCacheJavaLangObject, 0, { } },
-    // kProtoCache_Thread
-    { kClassCacheJavaLangThread, 0, { } },
-    // kProtoCacheJ_B
-    { kClassCacheByte, 1, { kClassCacheLong } },
-    // kProtoCacheJ_I
-    { kClassCacheInt, 1, { kClassCacheLong } },
-    // kProtoCacheJ_S
-    { kClassCacheShort, 1, { kClassCacheLong } },
-    // kProtoCacheJB_V
-    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
-    // kProtoCacheJI_V
-    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
-    // kProtoCacheJJ_J
-    { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheJJ_I
-    { kClassCacheInt, 2, { kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheJJ_V
-    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheJS_V
-    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
-    // kProtoCacheObject_Z
-    { kClassCacheBoolean, 1, { kClassCacheJavaLangObject } },
-    // kProtoCacheJI_J
-    { kClassCacheLong, 2, { kClassCacheLong, kClassCacheInt } },
-    // kProtoCacheObjectJII_Z
-    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
-        kClassCacheInt, kClassCacheInt } },
-    // kProtoCacheObjectJJJ_Z
-    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
-        kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheObjectJObjectObject_Z
-    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
-        kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
-    // kProtoCacheObjectJ_I
-    { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
-    // kProtoCacheObjectJI_I
-    { kClassCacheInt, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
-    // kProtoCacheObjectJI_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
-    // kProtoCacheObjectJ_J
-    { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
-    // kProtoCacheObjectJJ_J
-    { kClassCacheLong, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheObjectJJ_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
-    // kProtoCacheObjectJ_Object
-    { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
-    // kProtoCacheObjectJObject_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
-        kClassCacheJavaLangObject } },
-    // kProtoCacheObjectJObject_Object
-    { kClassCacheJavaLangObject, 3, { kClassCacheJavaLangObject, kClassCacheLong,
-        kClassCacheJavaLangObject } },
-    // kProtoCacheCharArrayICharArrayII_V
-    { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt,
-        kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} },
-    // kProtoCacheObjectIObjectII_V
-    { kClassCacheVoid, 5, {kClassCacheJavaLangObject, kClassCacheInt,
-        kClassCacheJavaLangObject, kClassCacheInt, kClassCacheInt} },
-    // kProtoCacheIICharArrayI_V
-    { kClassCacheVoid, 4, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray,
-        kClassCacheInt } },
-    // kProtoCacheByteArrayIII_String
-    { kClassCacheJavaLangString, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
-        kClassCacheInt } },
-    // kProtoCacheIICharArray_String
-    { kClassCacheJavaLangString, 3, { kClassCacheInt, kClassCacheInt,
-        kClassCacheJavaLangCharArray } },
-    // kProtoCacheString_String
-    { kClassCacheJavaLangString, 1, { kClassCacheJavaLangString } },
-    // kProtoCache_V
-    { kClassCacheVoid, 0, { } },
-    // kProtoCacheByteArray_V
-    { kClassCacheVoid, 1, { kClassCacheJavaLangByteArray } },
-    // kProtoCacheByteArrayI_V
-    { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheInt } },
-    // kProtoCacheByteArrayII_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt } },
-    // kProtoCacheByteArrayIII_V
-    { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
-        kClassCacheInt } },
-    // kProtoCacheByteArrayIIString_V
-    { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
-        kClassCacheJavaLangString } },
-    // kProtoCacheByteArrayString_V
-    { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaLangString } },
-    // kProtoCacheByteArrayIICharset_V
-    { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
-        kClassCacheJavaNioCharsetCharset } },
-    // kProtoCacheByteArrayCharset_V
-    { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaNioCharsetCharset } },
-    // kProtoCacheCharArray_V
-    { kClassCacheVoid, 1, { kClassCacheJavaLangCharArray } },
-    // kProtoCacheCharArrayII_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt } },
-    // kProtoCacheIICharArray_V
-    { kClassCacheVoid, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } },
-    // kProtoCacheIntArrayII_V
-    { kClassCacheVoid, 3, { kClassCacheJavaLangIntArray, kClassCacheInt, kClassCacheInt } },
-    // kProtoCacheString_V
-    { kClassCacheVoid, 1, { kClassCacheJavaLangString } },
-    // kProtoCacheStringBuffer_V
-    { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuffer } },
-    // kProtoCacheStringBuilder_V
-    { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuilder } },
-};
-
-const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
-    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
-
-    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, kIntrinsicFlagToFloatingPoint),
-    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
-    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint),
-
-    INTRINSIC(JavaLangFloat, FloatToIntBits, F_I, kIntrinsicFloat2Int, 0),
-    INTRINSIC(JavaLangDouble, DoubleToLongBits, D_J, kIntrinsicDouble2Long, 0),
-
-    INTRINSIC(JavaLangFloat, IsInfinite, F_Z, kIntrinsicFloatIsInfinite, 0),
-    INTRINSIC(JavaLangDouble, IsInfinite, D_Z, kIntrinsicDoubleIsInfinite, 0),
-    INTRINSIC(JavaLangFloat, IsNaN, F_Z, kIntrinsicFloatIsNaN, 0),
-    INTRINSIC(JavaLangDouble, IsNaN, D_Z, kIntrinsicDoubleIsNaN, 0),
-
-    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
-    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
-    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-    INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32),
-    INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64),
-
-    INTRINSIC(JavaLangInteger, BitCount, I_I, kIntrinsicBitCount, k32),
-    INTRINSIC(JavaLangLong, BitCount, J_I, kIntrinsicBitCount, k64),
-    INTRINSIC(JavaLangInteger, Compare, II_I, kIntrinsicCompare, k32),
-    INTRINSIC(JavaLangLong, Compare, JJ_I, kIntrinsicCompare, k64),
-    INTRINSIC(JavaLangInteger, HighestOneBit, I_I, kIntrinsicHighestOneBit, k32),
-    INTRINSIC(JavaLangLong, HighestOneBit, J_J, kIntrinsicHighestOneBit, k64),
-    INTRINSIC(JavaLangInteger, LowestOneBit, I_I, kIntrinsicLowestOneBit, k32),
-    INTRINSIC(JavaLangLong, LowestOneBit, J_J, kIntrinsicLowestOneBit, k64),
-    INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32),
-    INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64),
-    INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32),
-    INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64),
-    INTRINSIC(JavaLangInteger, Signum, I_I, kIntrinsicSignum, k32),
-    INTRINSIC(JavaLangLong, Signum, J_I, kIntrinsicSignum, k64),
-
-    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangMath,       Abs, F_F, kIntrinsicAbsFloat, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
-    INTRINSIC(JavaLangMath,       Abs, D_D, kIntrinsicAbsDouble, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
-    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangMath,       Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangMath,       Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangMath,       Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
-
-    INTRINSIC(JavaLangMath,       Cos, D_D, kIntrinsicCos, 0),
-    INTRINSIC(JavaLangMath,       Sin, D_D, kIntrinsicSin, 0),
-    INTRINSIC(JavaLangMath,       Acos, D_D, kIntrinsicAcos, 0),
-    INTRINSIC(JavaLangMath,       Asin, D_D, kIntrinsicAsin, 0),
-    INTRINSIC(JavaLangMath,       Atan, D_D, kIntrinsicAtan, 0),
-    INTRINSIC(JavaLangMath,       Atan2, DD_D, kIntrinsicAtan2, 0),
-    INTRINSIC(JavaLangMath,       Cbrt, D_D, kIntrinsicCbrt, 0),
-    INTRINSIC(JavaLangMath,       Cosh, D_D, kIntrinsicCosh, 0),
-    INTRINSIC(JavaLangMath,       Exp, D_D, kIntrinsicExp, 0),
-    INTRINSIC(JavaLangMath,       Expm1, D_D, kIntrinsicExpm1, 0),
-    INTRINSIC(JavaLangMath,       Hypot, DD_D, kIntrinsicHypot, 0),
-    INTRINSIC(JavaLangMath,       Log, D_D, kIntrinsicLog, 0),
-    INTRINSIC(JavaLangMath,       Log10, D_D, kIntrinsicLog10, 0),
-    INTRINSIC(JavaLangMath,       NextAfter, DD_D, kIntrinsicNextAfter, 0),
-    INTRINSIC(JavaLangMath,       Sinh, D_D, kIntrinsicSinh, 0),
-    INTRINSIC(JavaLangMath,       Tan, D_D, kIntrinsicTan, 0),
-    INTRINSIC(JavaLangMath,       Tanh, D_D, kIntrinsicTanh, 0),
-    INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
-    INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
-    INTRINSIC(JavaLangMath,       Ceil, D_D, kIntrinsicCeil, 0),
-    INTRINSIC(JavaLangStrictMath, Ceil, D_D, kIntrinsicCeil, 0),
-    INTRINSIC(JavaLangMath,       Floor, D_D, kIntrinsicFloor, 0),
-    INTRINSIC(JavaLangStrictMath, Floor, D_D, kIntrinsicFloor, 0),
-    INTRINSIC(JavaLangMath,       Rint, D_D, kIntrinsicRint, 0),
-    INTRINSIC(JavaLangStrictMath, Rint, D_D, kIntrinsicRint, 0),
-    INTRINSIC(JavaLangMath,       Round, F_I, kIntrinsicRoundFloat, 0),
-    INTRINSIC(JavaLangStrictMath, Round, F_I, kIntrinsicRoundFloat, 0),
-    INTRINSIC(JavaLangMath,       Round, D_J, kIntrinsicRoundDouble, 0),
-    INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0),
-
-    INTRINSIC(JavaLangRefReference, ReferenceGetReferent, _Object, kIntrinsicReferenceGetReferent, 0),
-
-    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
-    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
-    INTRINSIC(JavaLangString, Equals, Object_Z, kIntrinsicEquals, 0),
-    INTRINSIC(JavaLangString, GetCharsNoCheck, IICharArrayI_V, kIntrinsicGetCharsNoCheck, 0),
-    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
-    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
-    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
-    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
-    INTRINSIC(JavaLangStringFactory, NewStringFromBytes, ByteArrayIII_String,
-              kIntrinsicNewStringFromBytes, kIntrinsicFlagNone),
-    INTRINSIC(JavaLangStringFactory, NewStringFromChars, IICharArray_String,
-              kIntrinsicNewStringFromChars, kIntrinsicFlagNone),
-    INTRINSIC(JavaLangStringFactory, NewStringFromString, String_String,
-              kIntrinsicNewStringFromString, kIntrinsicFlagNone),
-
-    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
-    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, k32),
-    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, k64),
-    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
-    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, k32),
-    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, k64),
-    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
-              kIntrinsicFlagNone),
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
-              kIntrinsicFlagIsLong),
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
-              kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
-    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              type_flags), \
-    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              (type_flags) | kIntrinsicFlagIsVolatile), \
-    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags), \
-    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              (type_flags) | kIntrinsicFlagIsVolatile), \
-    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              (type_flags) | kIntrinsicFlagIsOrdered)
-
-    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
-    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
-    UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
-    // 1.8
-    INTRINSIC(SunMiscUnsafe, GetAndAddInt, ObjectJI_I, kIntrinsicUnsafeGetAndAddInt, 0),
-    INTRINSIC(SunMiscUnsafe, GetAndAddLong, ObjectJJ_J, kIntrinsicUnsafeGetAndAddLong, 0),
-    INTRINSIC(SunMiscUnsafe, GetAndSetInt, ObjectJI_I, kIntrinsicUnsafeGetAndSetInt, 0),
-    INTRINSIC(SunMiscUnsafe, GetAndSetLong, ObjectJJ_J, kIntrinsicUnsafeGetAndSetLong, 0),
-    INTRINSIC(SunMiscUnsafe, GetAndSetObject, ObjectJObject_Object, kIntrinsicUnsafeGetAndSetObject, 0),
-    INTRINSIC(SunMiscUnsafe, LoadFence, _V, kIntrinsicUnsafeLoadFence, 0),
-    INTRINSIC(SunMiscUnsafe, StoreFence, _V, kIntrinsicUnsafeStoreFence, 0),
-    INTRINSIC(SunMiscUnsafe, FullFence, _V, kIntrinsicUnsafeFullFence, 0),
-
-    INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray,
-              0),
-    INTRINSIC(JavaLangSystem, ArrayCopy, ObjectIObjectII_V , kIntrinsicSystemArrayCopy,
-              0),
-
-    INTRINSIC(JavaLangInteger, RotateRight, II_I, kIntrinsicRotateRight, k32),
-    INTRINSIC(JavaLangLong, RotateRight, JI_J, kIntrinsicRotateRight, k64),
-    INTRINSIC(JavaLangInteger, RotateLeft, II_I, kIntrinsicRotateLeft, k32),
-    INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64),
-
-#undef INTRINSIC
-};
-
-DexFileMethodInliner::DexFileMethodInliner()
-    : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
-      dex_file_(nullptr) {
-  static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0");
-  static_assert(arraysize(kClassCacheNames) == kClassCacheLast,
-                "bad arraysize for kClassCacheNames");
-  static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0");
-  static_assert(arraysize(kNameCacheNames) == kNameCacheLast,
-                "bad arraysize for kNameCacheNames");
-  static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0");
-  static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast,
-                "bad arraysize kProtoCacheNames");
-}
-
-DexFileMethodInliner::~DexFileMethodInliner() {
-}
-
-bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
-  InlineMethod method;
-  bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method);
-  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
-}
-
-InlineMethodFlags DexFileMethodInliner::IsIntrinsicOrSpecial(uint32_t method_index) {
-  ReaderMutexLock mu(Thread::Current(), lock_);
-  auto it = inline_methods_.find(method_index);
-  if (it != inline_methods_.end()) {
-    DCHECK_NE(it->second.flags & (kInlineIntrinsic | kInlineSpecial), 0);
-    return it->second.flags;
-  } else {
-    return kNoInlineMethodFlags;
-  }
-}
-
-bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) {
-  ReaderMutexLock mu(Thread::Current(), lock_);
-  auto it = inline_methods_.find(method_index);
-  bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0);
-  if (res && intrinsic != nullptr) {
-    *intrinsic = it->second;
-  }
-  return res;
-}
-
-bool DexFileMethodInliner::IsSpecial(uint32_t method_index) {
-  ReaderMutexLock mu(Thread::Current(), lock_);
-  auto it = inline_methods_.find(method_index);
-  return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0;
-}
-
-uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
-                                              ClassCacheIndex index) {
-  uint32_t* class_index = &cache->class_indexes[index];
-  if (*class_index != kIndexUnresolved) {
-    return *class_index;
-  }
-
-  const DexFile::TypeId* type_id = dex_file->FindTypeId(kClassCacheNames[index]);
-  if (type_id == nullptr) {
-    *class_index = kIndexNotFound;
-    return *class_index;
-  }
-  *class_index = dex_file->GetIndexForTypeId(*type_id);
-  return *class_index;
-}
-
-uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
-                                             NameCacheIndex index) {
-  uint32_t* name_index = &cache->name_indexes[index];
-  if (*name_index != kIndexUnresolved) {
-    return *name_index;
-  }
-
-  const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
-  if (string_id == nullptr) {
-    *name_index = kIndexNotFound;
-    return *name_index;
-  }
-  *name_index = dex_file->GetIndexForStringId(*string_id);
-  return *name_index;
-}
-
-uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
-                                              ProtoCacheIndex index) {
-  uint32_t* proto_index = &cache->proto_indexes[index];
-  if (*proto_index != kIndexUnresolved) {
-    return *proto_index;
-  }
-
-  const ProtoDef& proto_def = kProtoCacheDefs[index];
-  uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
-  if (return_index == kIndexNotFound) {
-    *proto_index = kIndexNotFound;
-    return *proto_index;
-  }
-  uint16_t return_type = static_cast<uint16_t>(return_index);
-  DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
-
-  uint32_t signature_length = proto_def.param_count;
-  uint16_t signature_type_idxs[kProtoMaxParams];
-  for (uint32_t i = 0; i != signature_length; ++i) {
-    uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
-    if (param_index == kIndexNotFound) {
-      *proto_index = kIndexNotFound;
-      return *proto_index;
-    }
-    signature_type_idxs[i] = static_cast<uint16_t>(param_index);
-    DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
-  }
-
-  const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
-                                                           signature_length);
-  if (proto_id == nullptr) {
-    *proto_index = kIndexNotFound;
-    return *proto_index;
-  }
-  *proto_index = dex_file->GetIndexForProtoId(*proto_id);
-  return *proto_index;
-}
-
-uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
-                                               const MethodDef& method_def) {
-  uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
-  if (declaring_class_index == kIndexNotFound) {
-    return kIndexNotFound;
-  }
-  uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
-  if (name_index == kIndexNotFound) {
-    return kIndexNotFound;
-  }
-  uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
-  if (proto_index == kIndexNotFound) {
-    return kIndexNotFound;
-  }
-  const DexFile::MethodId* method_id =
-      dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
-                             dex_file->GetStringId(name_index),
-                             dex_file->GetProtoId(proto_index));
-  if (method_id == nullptr) {
-    return kIndexNotFound;
-  }
-  return dex_file->GetIndexForMethodId(*method_id);
-}
-
-DexFileMethodInliner::IndexCache::IndexCache() {
-  std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
-  std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
-  std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
-}
-
-void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
-  DCHECK(dex_file != nullptr);
-  DCHECK(dex_file_ == nullptr);
-  IndexCache cache;
-  for (const IntrinsicDef& def : kIntrinsicMethods) {
-    uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def);
-    if (method_idx != kIndexNotFound) {
-      DCHECK(inline_methods_.find(method_idx) == inline_methods_.end());
-      inline_methods_.Put(method_idx, def.intrinsic);
-    }
-  }
-  dex_file_ = dex_file;
-}
-
-bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
-  WriterMutexLock mu(Thread::Current(), lock_);
-  if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
-    inline_methods_.Put(method_idx, method);
-    return true;
-  } else {
-    if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
-      // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet.
-    } else {
-      LOG(WARNING) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline";
-    }
-    return false;
-  }
-}
-
-}  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
deleted file mode 100644
index f4ae5a5..0000000
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
-
-#include <stdint.h>
-
-#include "base/enums.h"
-#include "base/mutex.h"
-#include "base/macros.h"
-#include "safe_map.h"
-#include "dex_file.h"
-#include "quick/inline_method_analyser.h"
-
-namespace art {
-
-namespace verifier {
-class MethodVerifier;
-}  // namespace verifier
-
-enum OpSize {
-  k32,
-  k64,
-  kSignedHalf,
-  kSignedByte,
-};
-
-/**
- * Handles inlining of methods from a particular DexFile.
- *
- * Intrinsics are a special case of inline methods. The DexFile indices for
- * all the supported intrinsic methods are looked up once by the FindIntrinsics
- * function and cached by this class for quick lookup by the method index.
- *
- * TODO: Detect short methods (at least getters, setters and empty functions)
- * from the verifier and mark them for inlining. Inline these methods early
- * during compilation to allow further optimizations. Similarly, provide
- * additional information about intrinsics to the early phases of compilation.
- */
-class DexFileMethodInliner {
-  public:
-    DexFileMethodInliner();
-    ~DexFileMethodInliner();
-
-    /**
-     * Analyse method code to determine if the method is a candidate for inlining.
-     * If it is, record its data for later.
-     *
-     * @param verifier the method verifier holding data about the method to analyse.
-     * @return true if the method is a candidate for inlining, false otherwise.
-     */
-    bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
-        REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!lock_);
-
-    /**
-     * Check whether a particular method index corresponds to an intrinsic or special function.
-     */
-    InlineMethodFlags IsIntrinsicOrSpecial(uint32_t method_index) REQUIRES(!lock_);
-
-    /**
-     * Check whether a particular method index corresponds to an intrinsic function.
-     */
-    bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) REQUIRES(!lock_);
-
-    /**
-     * Check whether a particular method index corresponds to a special function.
-     */
-    bool IsSpecial(uint32_t method_index) REQUIRES(!lock_);
-
-    /**
-     * To avoid multiple lookups of a class by its descriptor, we cache its
-     * type index in the IndexCache. These are the indexes into the IndexCache
-     * class_indexes array.
-     */
-    enum ClassCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
-      kClassCacheFirst = 0,
-      kClassCacheBoolean = kClassCacheFirst,
-      kClassCacheByte,
-      kClassCacheChar,
-      kClassCacheShort,
-      kClassCacheInt,
-      kClassCacheLong,
-      kClassCacheFloat,
-      kClassCacheDouble,
-      kClassCacheVoid,
-      kClassCacheJavaLangByteArray,
-      kClassCacheJavaLangCharArray,
-      kClassCacheJavaLangIntArray,
-      kClassCacheJavaLangObject,
-      kClassCacheJavaLangRefReference,
-      kClassCacheJavaLangString,
-      kClassCacheJavaLangStringBuffer,
-      kClassCacheJavaLangStringBuilder,
-      kClassCacheJavaLangStringFactory,
-      kClassCacheJavaLangDouble,
-      kClassCacheJavaLangFloat,
-      kClassCacheJavaLangInteger,
-      kClassCacheJavaLangLong,
-      kClassCacheJavaLangShort,
-      kClassCacheJavaLangMath,
-      kClassCacheJavaLangStrictMath,
-      kClassCacheJavaLangThread,
-      kClassCacheJavaNioCharsetCharset,
-      kClassCacheLibcoreIoMemory,
-      kClassCacheSunMiscUnsafe,
-      kClassCacheJavaLangSystem,
-      kClassCacheLast
-    };
-
-    /**
-     * To avoid multiple lookups of a method name string, we cache its string
-     * index in the IndexCache. These are the indexes into the IndexCache
-     * name_indexes array.
-     */
-    enum NameCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
-      kNameCacheFirst = 0,
-      kNameCacheReverse =  kNameCacheFirst,
-      kNameCacheReverseBytes,
-      kNameCacheDoubleToRawLongBits,
-      kNameCacheLongBitsToDouble,
-      kNameCacheFloatToRawIntBits,
-      kNameCacheIntBitsToFloat,
-      kNameCacheAbs,
-      kNameCacheMax,
-      kNameCacheMin,
-      kNameCacheCos,
-      kNameCacheSin,
-      kNameCacheAcos,
-      kNameCacheAsin,
-      kNameCacheAtan,
-      kNameCacheAtan2,
-      kNameCacheCbrt,
-      kNameCacheCosh,
-      kNameCacheExp,
-      kNameCacheExpm1,
-      kNameCacheHypot,
-      kNameCacheLog,
-      kNameCacheLog10,
-      kNameCacheNextAfter,
-      kNameCacheSinh,
-      kNameCacheTan,
-      kNameCacheTanh,
-      kNameCacheSqrt,
-      kNameCacheCeil,
-      kNameCacheFloor,
-      kNameCacheRint,
-      kNameCacheRound,
-      kNameCacheReferenceGetReferent,
-      kNameCacheCharAt,
-      kNameCacheCompareTo,
-      kNameCacheEquals,
-      kNameCacheGetCharsNoCheck,
-      kNameCacheIsEmpty,
-      kNameCacheFloatToIntBits,
-      kNameCacheDoubleToLongBits,
-      kNameCacheIsInfinite,
-      kNameCacheIsNaN,
-      kNameCacheIndexOf,
-      kNameCacheLength,
-      kNameCacheInit,
-      kNameCacheNewStringFromBytes,
-      kNameCacheNewStringFromChars,
-      kNameCacheNewStringFromString,
-      kNameCacheCurrentThread,
-      kNameCachePeekByte,
-      kNameCachePeekIntNative,
-      kNameCachePeekLongNative,
-      kNameCachePeekShortNative,
-      kNameCachePokeByte,
-      kNameCachePokeIntNative,
-      kNameCachePokeLongNative,
-      kNameCachePokeShortNative,
-      kNameCacheCompareAndSwapInt,
-      kNameCacheCompareAndSwapLong,
-      kNameCacheCompareAndSwapObject,
-      kNameCacheGetInt,
-      kNameCacheGetIntVolatile,
-      kNameCachePutInt,
-      kNameCachePutIntVolatile,
-      kNameCachePutOrderedInt,
-      kNameCacheGetLong,
-      kNameCacheGetLongVolatile,
-      kNameCachePutLong,
-      kNameCachePutLongVolatile,
-      kNameCachePutOrderedLong,
-      kNameCacheGetObject,
-      kNameCacheGetObjectVolatile,
-      kNameCachePutObject,
-      kNameCachePutObjectVolatile,
-      kNameCachePutOrderedObject,
-      kNameCacheGetAndAddInt,
-      kNameCacheGetAndAddLong,
-      kNameCacheGetAndSetInt,
-      kNameCacheGetAndSetLong,
-      kNameCacheGetAndSetObject,
-      kNameCacheLoadFence,
-      kNameCacheStoreFence,
-      kNameCacheFullFence,
-      kNameCacheArrayCopy,
-      kNameCacheBitCount,
-      kNameCacheCompare,
-      kNameCacheHighestOneBit,
-      kNameCacheLowestOneBit,
-      kNameCacheNumberOfLeadingZeros,
-      kNameCacheNumberOfTrailingZeros,
-      kNameCacheRotateRight,
-      kNameCacheRotateLeft,
-      kNameCacheSignum,
-      kNameCacheLast
-    };
-
-    /**
-     * To avoid multiple lookups of a method signature, we cache its proto
-     * index in the IndexCache. These are the indexes into the IndexCache
-     * proto_indexes array.
-     */
-    enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
-      kProtoCacheFirst = 0,
-      kProtoCacheI_I = kProtoCacheFirst,
-      kProtoCacheJ_J,
-      kProtoCacheS_S,
-      kProtoCacheD_D,
-      kProtoCacheDD_D,
-      kProtoCacheF_F,
-      kProtoCacheFF_F,
-      kProtoCacheD_J,
-      kProtoCacheD_Z,
-      kProtoCacheJ_D,
-      kProtoCacheF_I,
-      kProtoCacheF_Z,
-      kProtoCacheI_F,
-      kProtoCacheII_I,
-      kProtoCacheI_C,
-      kProtoCacheString_I,
-      kProtoCache_Z,
-      kProtoCache_I,
-      kProtoCache_Object,
-      kProtoCache_Thread,
-      kProtoCacheJ_B,
-      kProtoCacheJ_I,
-      kProtoCacheJ_S,
-      kProtoCacheJB_V,
-      kProtoCacheJI_V,
-      kProtoCacheJJ_J,
-      kProtoCacheJJ_I,
-      kProtoCacheJJ_V,
-      kProtoCacheJS_V,
-      kProtoCacheObject_Z,
-      kProtoCacheJI_J,
-      kProtoCacheObjectJII_Z,
-      kProtoCacheObjectJJJ_Z,
-      kProtoCacheObjectJObjectObject_Z,
-      kProtoCacheObjectJ_I,
-      kProtoCacheObjectJI_I,
-      kProtoCacheObjectJI_V,
-      kProtoCacheObjectJ_J,
-      kProtoCacheObjectJJ_J,
-      kProtoCacheObjectJJ_V,
-      kProtoCacheObjectJ_Object,
-      kProtoCacheObjectJObject_V,
-      kProtoCacheObjectJObject_Object,
-      kProtoCacheCharArrayICharArrayII_V,
-      kProtoCacheObjectIObjectII_V,
-      kProtoCacheIICharArrayI_V,
-      kProtoCacheByteArrayIII_String,
-      kProtoCacheIICharArray_String,
-      kProtoCacheString_String,
-      kProtoCache_V,
-      kProtoCacheByteArray_V,
-      kProtoCacheByteArrayI_V,
-      kProtoCacheByteArrayII_V,
-      kProtoCacheByteArrayIII_V,
-      kProtoCacheByteArrayIIString_V,
-      kProtoCacheByteArrayString_V,
-      kProtoCacheByteArrayIICharset_V,
-      kProtoCacheByteArrayCharset_V,
-      kProtoCacheCharArray_V,
-      kProtoCacheCharArrayII_V,
-      kProtoCacheIICharArray_V,
-      kProtoCacheIntArrayII_V,
-      kProtoCacheString_V,
-      kProtoCacheStringBuffer_V,
-      kProtoCacheStringBuilder_V,
-      kProtoCacheLast
-    };
-
-  private:
-    /**
-     * The maximum number of method parameters we support in the ProtoDef.
-     */
-    static constexpr uint32_t kProtoMaxParams = 6;
-
-    /**
-     * The method signature (proto) definition using cached class indexes.
-     * The return_type and params are used with the IndexCache to look up
-     * appropriate class indexes to be passed to DexFile::FindProtoId().
-     */
-    struct ProtoDef {
-      ClassCacheIndex return_type;
-      uint8_t param_count;
-      ClassCacheIndex params[kProtoMaxParams];
-    };
-
-    /**
-     * The method definition using cached class, name and proto indexes.
-     * The class index, method name index and proto index are used with
-     * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
-     */
-    struct MethodDef {
-      ClassCacheIndex declaring_class;
-      NameCacheIndex name;
-      ProtoCacheIndex proto;
-    };
-
-    /**
-     * The definition of an intrinsic function binds the method definition
-     * to an Intrinsic.
-     */
-    struct IntrinsicDef {
-      MethodDef method_def;
-      InlineMethod intrinsic;
-    };
-
-    /**
-     * Cache for class, method name and method signature indexes used during
-     * intrinsic function lookup to avoid multiple lookups of the same items.
-     *
-     * Many classes have multiple intrinsics and/or they are used in multiple
-     * method signatures and we want to avoid repeated lookups since they are
-     * not exactly cheap. The method names and method signatures are sometimes
-     * reused and therefore cached as well.
-     */
-    struct IndexCache {
-      IndexCache();
-
-      uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
-      uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
-      uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
-    };
-
-    static const char* const kClassCacheNames[];
-    static const char* const kNameCacheNames[];
-    static const ProtoDef kProtoCacheDefs[];
-    static const IntrinsicDef kIntrinsicMethods[];
-
-    static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
-    static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
-
-    static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
-                                   ClassCacheIndex index);
-    static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
-                                  NameCacheIndex index);
-    static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
-                                   ProtoCacheIndex index);
-    static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
-                                    const MethodDef& method_def);
-
-    /**
-     * Find all known intrinsic methods in the dex_file and cache their indices.
-     *
-     * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
-     */
-    void FindIntrinsics(const DexFile* dex_file) REQUIRES(lock_);
-
-    friend class DexFileToMethodInlinerMap;
-
-    bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) REQUIRES(!lock_);
-
-    ReaderWriterMutex lock_;
-    /*
-     * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
-     */
-    SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
-    const DexFile* dex_file_;
-
-    DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
deleted file mode 100644
index 2fec183..0000000
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include <algorithm>
-#include <utility>
-#include "thread.h"
-#include "thread-inl.h"
-#include "base/mutex.h"
-#include "base/mutex-inl.h"
-#include "base/logging.h"
-#include "driver/compiler_driver.h"
-
-#include "dex_file_to_method_inliner_map.h"
-
-namespace art {
-
-DexFileToMethodInlinerMap::DexFileToMethodInlinerMap()
-    : lock_("DexFileToMethodInlinerMap lock", kDexFileToMethodInlinerMapLock) {
-}
-
-DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
-  for (auto& entry : inliners_) {
-    delete entry.second;
-  }
-}
-
-DexFileMethodInliner* DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) {
-  Thread* self = Thread::Current();
-  {
-    ReaderMutexLock mu(self, lock_);
-    auto it = inliners_.find(dex_file);
-    if (it != inliners_.end()) {
-      return it->second;
-    }
-  }
-
-  // We need to acquire our lock_ to modify inliners_ but we want to release it
-  // before we initialize the new inliner. However, we need to acquire the
-  // new inliner's lock_ before we release our lock_ to prevent another thread
-  // from using the uninitialized inliner. This requires explicit calls to
-  // ExclusiveLock()/ExclusiveUnlock() on one of the locks, the other one
-  // can use WriterMutexLock.
-  DexFileMethodInliner* locked_inliner;
-  {
-    WriterMutexLock mu(self, lock_);
-    DexFileMethodInliner** inliner = &inliners_[dex_file];  // inserts new entry if not found
-    if (*inliner) {
-      return *inliner;
-    }
-    *inliner = new DexFileMethodInliner;
-    DCHECK(*inliner != nullptr);
-    locked_inliner = *inliner;
-    locked_inliner->lock_.ExclusiveLock(self);  // Acquire inliner's lock_ before releasing lock_.
-  }
-  locked_inliner->FindIntrinsics(dex_file);
-  locked_inliner->lock_.ExclusiveUnlock(self);
-  return locked_inliner;
-}
-
-}  // namespace art
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h
deleted file mode 100644
index 215dc12..0000000
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
-#define ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
-
-#include <map>
-#include <vector>
-#include "base/macros.h"
-#include "base/mutex.h"
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class CompilerDriver;
-class DexFile;
-
-/**
- * Map each DexFile to its DexFileMethodInliner.
- *
- * The method inliner is created and initialized the first time it's requested
- * for a particular DexFile.
- */
-class DexFileToMethodInlinerMap {
-  public:
-    DexFileToMethodInlinerMap();
-    ~DexFileToMethodInlinerMap();
-
-    DexFileMethodInliner* GetMethodInliner(const DexFile* dex_file) NO_THREAD_SAFETY_ANALYSIS;
-        // TODO: There is an irregular non-scoped use of locks that defeats annotalysis with -O0.
-        // Fix the NO_THREAD_SAFETY_ANALYSIS when this works and add the appropriate LOCKS_EXCLUDED.
-
-  private:
-    ReaderWriterMutex lock_;
-    std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(lock_);
-
-    DISALLOW_COPY_AND_ASSIGN(DexFileToMethodInlinerMap);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 2532bda..932eb51 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -16,7 +16,6 @@
 
 #include "quick_compiler_callbacks.h"
 
-#include "quick/dex_file_to_method_inliner_map.h"
 #include "verifier/method_verifier-inl.h"
 #include "verification_results.h"
 
@@ -24,8 +23,6 @@
 
 void QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) {
   verification_results_->ProcessVerifiedMethod(verifier);
-  MethodReference ref = verifier->GetMethodReference();
-  method_inliner_map_->GetMethodInliner(ref.dex_file)->AnalyseMethodCode(verifier);
 }
 
 void QuickCompilerCallbacks::ClassRejected(ClassReference ref) {
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h
index 824194c..34fd88b 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -22,19 +22,15 @@
 namespace art {
 
 class VerificationResults;
-class DexFileToMethodInlinerMap;
 
 class QuickCompilerCallbacks FINAL : public CompilerCallbacks {
   public:
     QuickCompilerCallbacks(VerificationResults* verification_results,
-                           DexFileToMethodInlinerMap* method_inliner_map,
                            CompilerCallbacks::CallbackMode mode)
         : CompilerCallbacks(mode),
           verification_results_(verification_results),
-          method_inliner_map_(method_inliner_map),
           verifier_deps_(nullptr) {
       CHECK(verification_results != nullptr);
-      CHECK(method_inliner_map != nullptr);
     }
 
     ~QuickCompilerCallbacks() { }
@@ -59,7 +55,6 @@
 
   private:
     VerificationResults* const verification_results_;
-    DexFileToMethodInlinerMap* const method_inliner_map_;
     verifier::VerifierDeps* verifier_deps_;
 };
 
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 6863f42..5063d71 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -21,17 +21,14 @@
 #include "compiler_driver.h"
 #include "compiler_options.h"
 #include "dex/verification_results.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 
 namespace art {
 
 TEST(CompiledMethodStorage, Deduplicate) {
   CompilerOptions compiler_options;
   VerificationResults verification_results(&compiler_options);
-  DexFileToMethodInlinerMap method_inliner_map;
   CompilerDriver driver(&compiler_options,
                         &verification_results,
-                        &method_inliner_map,
                         Compiler::kOptimizing,
                         /* instruction_set_ */ kNone,
                         /* instruction_set_features */ nullptr,
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4b913f4..2d0dd3c 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -26,7 +26,7 @@
 #include "dex_compilation_unit.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 
 namespace art {
@@ -37,7 +37,7 @@
 
 inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa,
                                                            const DexCompilationUnit* mUnit) {
-  return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+  return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Decode();
 }
 
 inline mirror::Class* CompilerDriver::ResolveClass(
@@ -45,7 +45,7 @@
     Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
     const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
       *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
   DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
@@ -60,7 +60,7 @@
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   const DexFile::MethodId& referrer_method_id =
       mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
   return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
@@ -95,7 +95,7 @@
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
     uint32_t field_idx, bool is_static) {
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
                                  is_static);
 }
@@ -258,7 +258,7 @@
     ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
     uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) {
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   ArtMethod* resolved_method =
       check_incompatible_class_change
           ? mUnit->GetClassLinker()->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f1d3116..2ec3f16 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -44,9 +44,8 @@
 #include "dex/dex_to_dex_compiler.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
-#include "dex/quick/dex_file_method_inliner.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_options.h"
+#include "intrinsics_enum.h"
 #include "jni_internal.h"
 #include "object_lock.h"
 #include "runtime.h"
@@ -60,7 +59,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
@@ -353,7 +352,6 @@
 CompilerDriver::CompilerDriver(
     const CompilerOptions* compiler_options,
     VerificationResults* verification_results,
-    DexFileToMethodInlinerMap* method_inliner_map,
     Compiler::Kind compiler_kind,
     InstructionSet instruction_set,
     const InstructionSetFeatures* instruction_set_features,
@@ -370,7 +368,6 @@
     const ProfileCompilationInfo* profile_compilation_info)
     : compiler_options_(compiler_options),
       verification_results_(verification_results),
-      method_inliner_map_(method_inliner_map),
       compiler_(Compiler::Create(this, compiler_kind)),
       compiler_kind_(compiler_kind),
       instruction_set_(instruction_set == kArm ? kThumb2: instruction_set),
@@ -401,7 +398,6 @@
       dex_to_dex_references_(),
       current_dex_to_dex_methods_(nullptr) {
   DCHECK(compiler_options_ != nullptr);
-  DCHECK(method_inliner_map_ != nullptr);
 
   compiler_->Init();
 
@@ -463,6 +459,29 @@
 }
 #undef CREATE_TRAMPOLINE
 
+static void SetupIntrinsic(Thread* self,
+                           Intrinsics intrinsic,
+                           InvokeType invoke_type,
+                           const char* class_name,
+                           const char* method_name,
+                           const char* signature)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  PointerSize image_size = class_linker->GetImagePointerSize();
+  mirror::Class* cls = class_linker->FindSystemClass(self, class_name);
+  if (cls == nullptr) {
+    LOG(FATAL) << "Could not find class of intrinsic " << class_name;
+  }
+  ArtMethod* method = (invoke_type == kStatic || invoke_type == kDirect)
+      ? cls->FindDeclaredDirectMethod(method_name, signature, image_size)
+      : cls->FindDeclaredVirtualMethod(method_name, signature, image_size);
+  if (method == nullptr) {
+    LOG(FATAL) << "Could not find method of intrinsic " << class_name << method_name << signature;
+  }
+  DCHECK_EQ(method->GetInvokeType(), invoke_type);
+  method->SetIntrinsic(static_cast<uint32_t>(intrinsic));
+}
+
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files,
                                 TimingLogger* timings) {
@@ -477,6 +496,17 @@
   // 3) Attempt to verify all classes
   // 4) Attempt to initialize image classes, and trivially initialized classes
   PreCompile(class_loader, dex_files, timings);
+  if (IsBootImage()) {
+    // We don't need to setup the intrinsics for non boot image compilation, as
+    // those compilations will pick up a boot image that have the ArtMethod already
+    // set with the intrinsics flag.
+    ScopedObjectAccess soa(Thread::Current());
+#define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnvironmentOrCache, SideEffects, Exceptions, ClassName, MethodName, Signature) \
+  SetupIntrinsic(soa.Self(), Intrinsics::k##Name, InvokeType, ClassName, MethodName, Signature);
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+  }
   // Compile:
   // 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
   //    compilation.
@@ -535,7 +565,7 @@
   ScopedObjectAccess soa(self);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   return GetDexToDexCompilationLevel(self, driver, class_loader, dex_file, class_def);
 }
 
@@ -610,7 +640,7 @@
       ScopedObjectAccess soa(self);
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle(
-          soa.Decode<mirror::ClassLoader*>(class_loader)));
+          soa.Decode<mirror::ClassLoader>(class_loader)));
 
       // TODO: Lookup annotation from DexFile directly without resolving method.
       ArtMethod* method =
@@ -1626,7 +1656,7 @@
   {
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader())));
     resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
     referrer_class = resolved_field != nullptr
         ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
@@ -1970,7 +2000,7 @@
     ScopedObjectAccess soa(self);
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
         soa.Self(), dex_file, false)));
     // Resolve the class.
@@ -2067,7 +2097,7 @@
     const DexFile& dex_file = *manager_->GetDexFile();
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager_->GetClassLoader())));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(manager_->GetClassLoader())));
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
         dex_file,
         class_loader.Get())));
@@ -2166,7 +2196,7 @@
     jobject jclass_loader = manager_->GetClassLoader();
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     if (klass.Get() == nullptr) {
@@ -2254,7 +2284,7 @@
     jobject jclass_loader = manager_->GetClassLoader();
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     // Class might have failed resolution. Then don't set it to verified.
@@ -2316,7 +2346,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(manager_->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader)));
 
@@ -2551,7 +2581,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     Handle<mirror::DexCache> dex_cache;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 41f0d36..52a04cc 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -57,7 +57,6 @@
 class CompiledMethod;
 class CompilerOptions;
 class DexCompilationUnit;
-class DexFileToMethodInlinerMap;
 struct InlineIGetIPutData;
 class InstructionSetFeatures;
 class ParallelCompilationManager;
@@ -88,7 +87,6 @@
   // classes.
   CompilerDriver(const CompilerOptions* compiler_options,
                  VerificationResults* verification_results,
-                 DexFileToMethodInlinerMap* method_inliner_map,
                  Compiler::Kind compiler_kind,
                  InstructionSet instruction_set,
                  const InstructionSetFeatures* instruction_set_features,
@@ -133,10 +131,6 @@
     return verification_results_;
   }
 
-  DexFileToMethodInlinerMap* GetMethodInlinerMap() const {
-    return method_inliner_map_;
-  }
-
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
   }
@@ -603,7 +597,6 @@
 
   const CompilerOptions* const compiler_options_;
   VerificationResults* const verification_results_;
-  DexFileToMethodInlinerMap* const method_inliner_map_;
 
   std::unique_ptr<Compiler> compiler_;
   Compiler::Kind compiler_kind_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index b9a5a78..96f17ac 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -32,7 +32,7 @@
 #include "mirror/object-inl.h"
 #include "handle_scope-inl.h"
 #include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -83,7 +83,7 @@
       ScopedObjectAccess soa(Thread::Current());
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> loader(
-          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+          hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
       mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
       CHECK(c != nullptr);
       const auto pointer_size = class_linker->GetImagePointerSize();
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index ca0869a..0c06090 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -26,7 +26,7 @@
 #include "invoke_type.h"
 #include "mirror/object-inl.h"
 #include "oat.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 86f91c5..f9e5cb9 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -31,7 +31,7 @@
 #include "oat_quick_method_header.h"
 #include "optimizing/stack_map_stream.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
 
@@ -45,7 +45,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("ExceptionHandle"))));
     my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
     ASSERT_TRUE(my_klass_ != nullptr);
     Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
@@ -219,7 +219,7 @@
   ASSERT_TRUE(internal != nullptr);
   jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
   ASSERT_TRUE(ste_array != nullptr);
-  auto* trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+  auto trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
 
   ASSERT_TRUE(trace_array != nullptr);
   ASSERT_TRUE(trace_array->Get(0) != nullptr);
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index ea4b7ee..4689c9d 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -33,7 +33,7 @@
 #include "lock_word.h"
 #include "mirror/object-inl.h"
 #include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "signal_catcher.h"
 #include "utils.h"
 
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 6b5758b..41bda60 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -63,7 +63,7 @@
 #include "oat_file.h"
 #include "oat_file_manager.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 
diff --git a/compiler/intrinsics_enum.h b/compiler/intrinsics_enum.h
new file mode 100644
index 0000000..5528181
--- /dev/null
+++ b/compiler/intrinsics_enum.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_COMPILER_INTRINSICS_ENUM_H_
+#define ART_COMPILER_INTRINSICS_ENUM_H_
+
+namespace art {
+
+enum class Intrinsics {
+#define OPTIMIZING_INTRINSICS(Name, ...) \
+  k ## Name,
+#include "intrinsics_list.h"
+  kNone,
+  INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+};
+std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic);
+
+}  // namespace art
+
+#endif  // ART_COMPILER_INTRINSICS_ENUM_H_
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h
new file mode 100644
index 0000000..5877f57
--- /dev/null
+++ b/compiler/intrinsics_list.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C, "", "", "") 2015 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.
+ */
+
+#ifndef ART_COMPILER_INTRINSICS_LIST_H_
+#define ART_COMPILER_INTRINSICS_LIST_H_
+
+// All intrinsics supported by ART. Format is name, then whether it is expected
+// to be a HInvokeStaticOrDirect node (compared to HInvokeVirtual), then whether it requires an
+// environment, may have side effects, or may throw exceptions.
+
+// Note: adding a new intrinsic requires an art image version change,
+// as the modifiers flag for some ArtMethods will need to be changed.
+
+#define INTRINSICS_LIST(V) \
+  V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J") \
+  V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToLongBits", "(D)J") \
+  V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "isInfinite", "(D)Z") \
+  V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "isNaN", "(D)Z") \
+  V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "longBitsToDouble", "(J)D") \
+  V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "floatToRawIntBits", "(F)I") \
+  V(FloatFloatToIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "floatToIntBits", "(F)I") \
+  V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "isInfinite", "(F)Z") \
+  V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "isNaN", "(F)Z") \
+  V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "intBitsToFloat", "(I)F") \
+  V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "reverse", "(I)I") \
+  V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "reverseBytes", "(I)I") \
+  V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "bitCount", "(I)I") \
+  V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "compare", "(II)I") \
+  V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "highestOneBit", "(I)I") \
+  V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "lowestOneBit", "(I)I") \
+  V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "numberOfLeadingZeros", "(I)I") \
+  V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "numberOfTrailingZeros", "(I)I") \
+  V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "rotateRight", "(II)I") \
+  V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "rotateLeft", "(II)I") \
+  V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "signum", "(I)I") \
+  V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "reverse", "(J)J") \
+  V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "reverseBytes", "(J)J") \
+  V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "bitCount", "(J)I") \
+  V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "compare", "(JJ)I") \
+  V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "highestOneBit", "(J)J") \
+  V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "lowestOneBit", "(J)J") \
+  V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "numberOfLeadingZeros", "(J)I") \
+  V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "numberOfTrailingZeros", "(J)I") \
+  V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "rotateRight", "(JI)J") \
+  V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "rotateLeft", "(JI)J") \
+  V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "signum", "(J)I") \
+  V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Short;", "reverseBytes", "(S)S") \
+  V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(D)D") \
+  V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(F)F") \
+  V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(J)J") \
+  V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(I)I") \
+  V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(DD)D") \
+  V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(FF)F") \
+  V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(JJ)J") \
+  V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(II)I") \
+  V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(DD)D") \
+  V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(FF)F") \
+  V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(JJ)J") \
+  V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(II)I") \
+  V(MathCos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cos", "(D)D") \
+  V(MathSin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sin", "(D)D") \
+  V(MathAcos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "acos", "(D)D") \
+  V(MathAsin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "asin", "(D)D") \
+  V(MathAtan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "atan", "(D)D") \
+  V(MathAtan2, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "atan2", "(DD)D") \
+  V(MathCbrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cbrt", "(D)D") \
+  V(MathCosh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cosh", "(D)D") \
+  V(MathExp, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "exp", "(D)D") \
+  V(MathExpm1, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "expm1", "(D)D") \
+  V(MathHypot, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "hypot", "(DD)D") \
+  V(MathLog, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "log", "(D)D") \
+  V(MathLog10, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "log10", "(D)D") \
+  V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "nextAfter", "(DD)D") \
+  V(MathSinh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sinh", "(D)D") \
+  V(MathTan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "tan", "(D)D") \
+  V(MathTanh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "tanh", "(D)D") \
+  V(MathSqrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sqrt", "(D)D") \
+  V(MathCeil, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "ceil", "(D)D") \
+  V(MathFloor, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "floor", "(D)D") \
+  V(MathRint, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "rint", "(D)D") \
+  V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "round", "(D)J") \
+  V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "round", "(F)I") \
+  V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/System;", "arraycopy", "([CI[CII)V") \
+  V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/System;", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V") \
+  V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Thread;", "currentThread", "()Ljava/lang/Thread;") \
+  V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekByte", "(J)B") \
+  V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekIntNative", "(J)I") \
+  V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekLongNative", "(J)J") \
+  V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekShortNative", "(J)S") \
+  V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeByte", "(JB)V") \
+  V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeIntNative", "(JI)V") \
+  V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeLongNative", "(JJ)V") \
+  V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeShortNative", "(JS)V") \
+  V(StringCharAt, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "charAt", "(I)C") \
+  V(StringCompareTo, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I") \
+  V(StringEquals, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z") \
+  V(StringGetCharsNoCheck, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "getCharsNoCheck", "(II[CI)V") \
+  V(StringIndexOf, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "indexOf", "(I)I") \
+  V(StringIndexOfAfter, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "indexOf", "(II)I") \
+  V(StringIsEmpty, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/String;", "isEmpty", "()Z") \
+  V(StringLength, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/String;", "length", "()I") \
+  V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromBytes", "([BIII)Ljava/lang/String;") \
+  V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromChars", "(II[C)Ljava/lang/String;") \
+  V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;") \
+  V(UnsafeCASInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapInt", "(Ljava/lang/Object;JII)Z") \
+  V(UnsafeCASLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z") \
+  V(UnsafeCASObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapObject", "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \
+  V(UnsafeGet, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getInt", "(Ljava/lang/Object;J)I") \
+  V(UnsafeGetVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getIntVolatile", "(Ljava/lang/Object;J)I") \
+  V(UnsafeGetObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;") \
+  V(UnsafeGetObjectVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;") \
+  V(UnsafeGetLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLong", "(Ljava/lang/Object;J)J") \
+  V(UnsafeGetLongVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLongVolatile", "(Ljava/lang/Object;J)J") \
+  V(UnsafePut, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putInt", "(Ljava/lang/Object;JI)V") \
+  V(UnsafePutOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedInt", "(Ljava/lang/Object;JI)V") \
+  V(UnsafePutVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putIntVolatile", "(Ljava/lang/Object;JI)V") \
+  V(UnsafePutObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+  V(UnsafePutObjectOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedObject", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+  V(UnsafePutObjectVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+  V(UnsafePutLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLong", "(Ljava/lang/Object;JJ)V") \
+  V(UnsafePutLongOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedLong", "(Ljava/lang/Object;JJ)V") \
+  V(UnsafePutLongVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLongVolatile", "(Ljava/lang/Object;JJ)V") \
+  V(UnsafeGetAndAddInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddInt", "(Ljava/lang/Object;JI)I") \
+  V(UnsafeGetAndAddLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddLong", "(Ljava/lang/Object;JJ)J") \
+  V(UnsafeGetAndSetInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetInt", "(Ljava/lang/Object;JI)I") \
+  V(UnsafeGetAndSetLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetLong", "(Ljava/lang/Object;JJ)J") \
+  V(UnsafeGetAndSetObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetObject", "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;") \
+  V(UnsafeLoadFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "loadFence", "()V") \
+  V(UnsafeStoreFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "storeFence", "()V") \
+  V(UnsafeFullFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "fullFence", "()V") \
+  V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/ref/Reference;", "getReferent", "()Ljava/lang/Object;")
+
+#endif  // ART_COMPILER_INTRINSICS_LIST_H_
+#undef ART_COMPILER_INTRINSICS_LIST_H_   // #define is only for lint.
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 7246ace..4f86905 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -150,11 +150,9 @@
     instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
   }
   cumulative_logger_.reset(new CumulativeLogger("jit times"));
-  method_inliner_map_.reset(new DexFileToMethodInlinerMap);
   compiler_driver_.reset(new CompilerDriver(
       compiler_options_.get(),
       /* verification_results */ nullptr,
-      method_inliner_map_.get(),
       Compiler::kOptimizing,
       instruction_set,
       instruction_set_features_.get(),
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index 18e3155..ea2747c 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -19,7 +19,6 @@
 
 #include "base/mutex.h"
 #include "compiled_method.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 
@@ -49,7 +48,6 @@
  private:
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<CumulativeLogger> cumulative_logger_;
-  std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
   std::unique_ptr<File> perf_file_;
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index b692c6d..19d55a3 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -36,7 +36,7 @@
 #include "nativeloader/native_loader.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_bar(JNIEnv*, jobject, jint count) {
@@ -238,7 +238,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
     // Compile the native method before starting the runtime
     mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
     const auto pointer_size = class_linker_->GetImagePointerSize();
@@ -431,6 +431,7 @@
   TEST_F(JniCompilerTest, TestName ## CriticalGeneric) { \
     SCOPED_TRACE("@CriticalNative JNI with generic");  \
     gCurrentJni = static_cast<uint32_t>(JniKind::kCritical); \
+    SetCheckGenericJni(true);                    \
     TestName ## Impl();                          \
   }
 
@@ -1139,8 +1140,8 @@
     // Build stack trace
     jobject internal = Thread::Current()->CreateInternalStackTrace<false>(soa);
     jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
-    mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
-        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+    ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> trace_array =
+        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
     EXPECT_TRUE(trace_array != nullptr);
     EXPECT_EQ(11, trace_array->GetLength());
 
@@ -1204,7 +1205,7 @@
   // Add 10 local references
   ScopedObjectAccess soa(env);
   for (int i = 0; i < 10; i++) {
-    soa.AddLocalReference<jobject>(soa.Decode<mirror::Object*>(thisObj));
+    soa.AddLocalReference<jobject>(soa.Decode<mirror::Object>(thisObj));
   }
   return x+1;
 }
@@ -1282,7 +1283,7 @@
 
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
-  EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object*>(thisObj)));
+  EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object>(thisObj).Decode()));
   return nullptr;
 }
 
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 304b31c..62b3a0a 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -22,7 +22,6 @@
 #include "base/array_ref.h"
 #include "base/macros.h"
 #include "compiled_method.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
@@ -43,10 +42,8 @@
   RelativePatcherTest(InstructionSet instruction_set, const std::string& variant)
       : compiler_options_(),
         verification_results_(&compiler_options_),
-        inliner_map_(),
         driver_(&compiler_options_,
                 &verification_results_,
-                &inliner_map_,
                 Compiler::kQuick,
                 instruction_set,
                 /* instruction_set_features*/ nullptr,
@@ -269,7 +266,6 @@
 
   CompilerOptions compiler_options_;
   VerificationResults verification_results_;
-  DexFileToMethodInlinerMap inliner_map_;
   CompilerDriver driver_;  // Needed for constructing CompiledMethod.
   std::string error_msg_;
   InstructionSet instruction_set_;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 24d102d..e8bc67d 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -23,7 +23,6 @@
 #include "compiled_method.h"
 #include "compiler.h"
 #include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
@@ -38,7 +37,7 @@
 #include "mirror/object_array-inl.h"
 #include "oat_file-inl.h"
 #include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils/test_dex_file_builder.h"
 
 namespace art {
@@ -100,15 +99,12 @@
       compiler_options_->ParseCompilerOption(option, Usage);
     }
     verification_results_.reset(new VerificationResults(compiler_options_.get()));
-    method_inliner_map_.reset(new DexFileToMethodInlinerMap);
     callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
-                                                method_inliner_map_.get(),
                                                 CompilerCallbacks::CallbackMode::kCompileApp));
     Runtime::Current()->SetCompilerCallbacks(callbacks_.get());
     timer_.reset(new CumulativeLogger("Compilation times"));
     compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                               verification_results_.get(),
-                                              method_inliner_map_.get(),
                                               compiler_kind,
                                               insn_set,
                                               insn_features_.get(),
@@ -501,7 +497,8 @@
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   for (const DexFile* dex_file : dex_files) {
     ScopedObjectAccess soa(Thread::Current());
-    class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader*>(class_loader));
+    class_linker->RegisterDexFile(*dex_file,
+                                  soa.Decode<mirror::ClassLoader>(class_loader).Decode());
   }
   compiler_driver_->SetDexFilesForOatFile(dex_files);
   compiler_driver_->CompileAll(class_loader, dex_files, &timings);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c840a9e..54ec7c1 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -50,7 +50,7 @@
 #include "oat_quick_method_header.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "type_lookup_table.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "vdex_file.h"
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 55e1221..681988d 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4589,7 +4589,9 @@
   }
   // We need a temporary register for the read barrier marking slow
   // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
-  if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
+  // Also need for String compression feature.
+  if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
+      || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
     locations->AddTemp(Location::RequiresRegister());
   }
 }
@@ -4602,6 +4604,8 @@
   Location out_loc = locations->Out();
   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
   Primitive::Type type = instruction->GetType();
+  const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
+                                        instruction->IsStringCharAt();
   HInstruction* array_instr = instruction->GetArray();
   bool has_intermediate_address = array_instr->IsIntermediateAddress();
   // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
@@ -4615,10 +4619,31 @@
     case Primitive::kPrimInt: {
       if (index.IsConstant()) {
         int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
-        uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
+        if (maybe_compressed_char_at) {
+          Register length = IP;
+          Label uncompressed_load, done;
+          uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+          __ LoadFromOffset(kLoadWord, length, obj, count_offset);
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ cmp(length, ShifterOperand(0));
+          __ b(&uncompressed_load, GE);
+          __ LoadFromOffset(kLoadUnsignedByte,
+                            out_loc.AsRegister<Register>(),
+                            obj,
+                            data_offset + const_index);
+          __ b(&done);
+          __ Bind(&uncompressed_load);
+          __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
+                            out_loc.AsRegister<Register>(),
+                            obj,
+                            data_offset + (const_index << 1));
+          __ Bind(&done);
+        } else {
+          uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
 
-        LoadOperandType load_type = GetLoadOperandType(type);
-        __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
+          LoadOperandType load_type = GetLoadOperandType(type);
+          __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
+        }
       } else {
         Register temp = IP;
 
@@ -4634,7 +4659,24 @@
         } else {
           __ add(temp, obj, ShifterOperand(data_offset));
         }
-        codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
+        if (maybe_compressed_char_at) {
+          Label uncompressed_load, done;
+          uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+          Register length = locations->GetTemp(0).AsRegister<Register>();
+          __ LoadFromOffset(kLoadWord, length, obj, count_offset);
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ cmp(length, ShifterOperand(0));
+          __ b(&uncompressed_load, GE);
+          __ ldrb(out_loc.AsRegister<Register>(),
+                  Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
+          __ b(&done);
+          __ Bind(&uncompressed_load);
+          __ ldrh(out_loc.AsRegister<Register>(),
+                  Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
+          __ Bind(&done);
+        } else {
+          codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
+        }
       }
       break;
     }
@@ -4734,7 +4776,7 @@
   if (type == Primitive::kPrimNot) {
     // Potential implicit null checks, in the case of reference
     // arrays, are handled in the previous switch statement.
-  } else {
+  } else if (!maybe_compressed_char_at) {
     codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
 }
@@ -5024,6 +5066,10 @@
   Register out = locations->Out().AsRegister<Register>();
   __ LoadFromOffset(kLoadWord, out, obj, offset);
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+  // Mask out compression flag from String's array length.
+  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+    __ bic(out, out, ShifterOperand(1u << 31));
+  }
 }
 
 void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a2a2e42..4f7f36b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2052,7 +2052,8 @@
   Location index = locations->InAt(1);
   Location out = locations->Out();
   uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
-
+  const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
+                                        instruction->IsStringCharAt();
   MacroAssembler* masm = GetVIXLAssembler();
   UseScratchRegisterScope temps(masm);
   // Block pools between `Load` and `MaybeRecordImplicitNullCheck`.
@@ -2070,9 +2071,28 @@
   } else {
     // General case.
     MemOperand source = HeapOperand(obj);
+    Register length;
+    if (maybe_compressed_char_at) {
+      uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+      length = temps.AcquireW();
+      __ Ldr(length, HeapOperand(obj, count_offset));
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+    }
     if (index.IsConstant()) {
-      offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
-      source = HeapOperand(obj, offset);
+      if (maybe_compressed_char_at) {
+        vixl::aarch64::Label uncompressed_load, done;
+        __ Tbz(length.W(), kWRegSize - 1, &uncompressed_load);
+        __ Ldrb(Register(OutputCPURegister(instruction)),
+                HeapOperand(obj, offset + Int64ConstantFrom(index)));
+        __ B(&done);
+        __ Bind(&uncompressed_load);
+        __ Ldrh(Register(OutputCPURegister(instruction)),
+                HeapOperand(obj, offset + (Int64ConstantFrom(index) << 1)));
+        __ Bind(&done);
+      } else {
+        offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+        source = HeapOperand(obj, offset);
+      }
     } else {
       Register temp = temps.AcquireSameSizeAs(obj);
       if (instruction->GetArray()->IsIntermediateAddress()) {
@@ -2090,11 +2110,24 @@
       } else {
         __ Add(temp, obj, offset);
       }
-      source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+      if (maybe_compressed_char_at) {
+        vixl::aarch64::Label uncompressed_load, done;
+        __ Tbz(length.W(), kWRegSize - 1, &uncompressed_load);
+        __ Ldrb(Register(OutputCPURegister(instruction)),
+                HeapOperand(temp, XRegisterFrom(index), LSL, 0));
+        __ B(&done);
+        __ Bind(&uncompressed_load);
+        __ Ldrh(Register(OutputCPURegister(instruction)),
+                HeapOperand(temp, XRegisterFrom(index), LSL, 1));
+        __ Bind(&done);
+      } else {
+        source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+      }
     }
-
-    codegen_->Load(type, OutputCPURegister(instruction), source);
-    codegen_->MaybeRecordImplicitNullCheck(instruction);
+    if (!maybe_compressed_char_at) {
+      codegen_->Load(type, OutputCPURegister(instruction), source);
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+    }
 
     if (type == Primitive::kPrimNot) {
       static_assert(
@@ -2118,9 +2151,14 @@
 
 void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
   uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
+  vixl::aarch64::Register out = OutputRegister(instruction);
   BlockPoolsScope block_pools(GetVIXLAssembler());
-  __ Ldr(OutputRegister(instruction), HeapOperand(InputRegisterAt(instruction, 0), offset));
+  __ Ldr(out, HeapOperand(InputRegisterAt(instruction, 0), offset));
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+  // Mask out compression flag from String's array length.
+  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+    __ And(out.W(), out.W(), Operand(static_cast<int32_t>(INT32_MAX)));
+  }
 }
 
 void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
@@ -2312,7 +2350,6 @@
   BoundsCheckSlowPathARM64* slow_path =
       new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(instruction);
   codegen_->AddSlowPath(slow_path);
-
   __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
   __ B(slow_path->GetEntryLabel(), hs);
 }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index c300080..a7051ae 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -150,6 +150,9 @@
         length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
       }
       __ movl(length_loc.AsRegister<Register>(), array_len);
+      if (mirror::kUseStringCompression) {
+        __ andl(length_loc.AsRegister<Register>(), Immediate(INT32_MAX));
+      }
     }
     x86_codegen->EmitParallelMoves(
         locations->InAt(0),
@@ -5021,7 +5024,23 @@
 
     case Primitive::kPrimChar: {
       Register out = out_loc.AsRegister<Register>();
-      __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+      if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+        // Branch cases into compressed and uncompressed for each index's type.
+        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+        NearLabel done, not_compressed;
+        __ cmpl(Address(obj, count_offset), Immediate(0));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ j(kGreaterEqual, &not_compressed);
+        __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
+        __ jmp(&done);
+        __ Bind(&not_compressed);
+        __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+        __ Bind(&done);
+      } else {
+        // Common case for charAt of array of char or when string compression's
+        // feature is turned off.
+        __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+      }
       break;
     }
 
@@ -5359,6 +5378,10 @@
   Register out = locations->Out().AsRegister<Register>();
   __ movl(out, Address(obj, offset));
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+  // Mask out most significant bit in case the array is String's array of char.
+  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+    __ andl(out, Immediate(INT32_MAX));
+  }
 }
 
 void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -5372,9 +5395,15 @@
   if (!length->IsEmittedAtUseSite()) {
     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   }
+  // Need register to see array's length.
+  if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+    locations->AddTemp(Location::RequiresRegister());
+  }
 }
 
 void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
+  const bool is_string_compressed_char_at =
+      mirror::kUseStringCompression && instruction->IsStringCharAt();
   LocationSummary* locations = instruction->GetLocations();
   Location index_loc = locations->InAt(0);
   Location length_loc = locations->InAt(1);
@@ -5409,13 +5438,23 @@
       uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
       Location array_loc = array_length->GetLocations()->InAt(0);
       Address array_len(array_loc.AsRegister<Register>(), len_offset);
-      if (index_loc.IsConstant()) {
-        int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
-        __ cmpl(array_len, Immediate(value));
+      if (is_string_compressed_char_at) {
+        Register length_reg = locations->GetTemp(0).AsRegister<Register>();
+        __ movl(length_reg, array_len);
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
+        __ andl(length_reg, Immediate(INT32_MAX));
+        codegen_->GenerateIntCompare(length_reg, index_loc);
       } else {
-        __ cmpl(array_len, index_loc.AsRegister<Register>());
+        // Checking bounds for general case:
+        // Array of char or string's array with feature compression off.
+        if (index_loc.IsConstant()) {
+          int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+          __ cmpl(array_len, Immediate(value));
+        } else {
+          __ cmpl(array_len, index_loc.AsRegister<Register>());
+        }
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
       }
-      codegen_->MaybeRecordImplicitNullCheck(array_length);
     } else {
       codegen_->GenerateIntCompare(length_loc, index_loc);
     }
@@ -7278,13 +7317,17 @@
 
 void CodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
   Register lhs_reg = lhs.AsRegister<Register>();
+  GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86::GenerateIntCompare(Register lhs, Location rhs) {
   if (rhs.IsConstant()) {
     int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-    Compare32BitValue(lhs_reg, value);
+    Compare32BitValue(lhs, value);
   } else if (rhs.IsStackSlot()) {
-    __ cmpl(lhs_reg, Address(ESP, rhs.GetStackIndex()));
+    __ cmpl(lhs, Address(ESP, rhs.GetStackIndex()));
   } else {
-    __ cmpl(lhs_reg, rhs.AsRegister<Register>());
+    __ cmpl(lhs, rhs.AsRegister<Register>());
   }
 }
 
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 1ae9af3..1bd28da 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -474,6 +474,7 @@
 
   // Compare int values. Supports only register locations for `lhs`.
   void GenerateIntCompare(Location lhs, Location rhs);
+  void GenerateIntCompare(Register lhs, Location rhs);
 
   // Construct address for array access.
   static Address ArrayAddress(Register obj,
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index f9a3e42..b243ee0 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -198,6 +198,9 @@
         length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
       }
       __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
+      if (mirror::kUseStringCompression) {
+        __ andl(length_loc.AsRegister<CpuRegister>(), Immediate(INT32_MAX));
+      }
     }
 
     // We're moving two locations to locations that could overlap, so we need a parallel
@@ -4485,7 +4488,21 @@
 
     case Primitive::kPrimChar: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
-      __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+      if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+        // Branch cases into compressed and uncompressed for each index's type.
+        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+        NearLabel done, not_compressed;
+        __ cmpl(Address(obj, count_offset), Immediate(0));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ j(kGreaterEqual, &not_compressed);
+        __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
+        __ jmp(&done);
+        __ Bind(&not_compressed);
+        __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+        __ Bind(&done);
+      } else {
+        __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+      }
       break;
     }
 
@@ -4807,6 +4824,10 @@
   CpuRegister out = locations->Out().AsRegister<CpuRegister>();
   __ movl(out, Address(obj, offset));
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+  // Mask out most significant bit in case the array is String's array of char.
+  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+    __ andl(out, Immediate(INT32_MAX));
+  }
 }
 
 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -4856,13 +4877,23 @@
       uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
       Location array_loc = array_length->GetLocations()->InAt(0);
       Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
-      if (index_loc.IsConstant()) {
-        int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
-        __ cmpl(array_len, Immediate(value));
+      if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+        CpuRegister length_reg = CpuRegister(TMP);
+        __ movl(length_reg, array_len);
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
+        __ andl(length_reg, Immediate(INT32_MAX));
+        codegen_->GenerateIntCompare(length_reg, index_loc);
       } else {
-        __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+        // Checking the bound for general case:
+        // Array of char or String's array when the compression feature off.
+        if (index_loc.IsConstant()) {
+          int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+          __ cmpl(array_len, Immediate(value));
+        } else {
+          __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+        }
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
       }
-      codegen_->MaybeRecordImplicitNullCheck(array_length);
     } else {
       codegen_->GenerateIntCompare(length_loc, index_loc);
     }
@@ -6525,13 +6556,17 @@
 
 void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
   CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
+  GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
   if (rhs.IsConstant()) {
     int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-    Compare32BitValue(lhs_reg, value);
+    Compare32BitValue(lhs, value);
   } else if (rhs.IsStackSlot()) {
-    __ cmpl(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+    __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
   } else {
-    __ cmpl(lhs_reg, rhs.AsRegister<CpuRegister>());
+    __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
   }
 }
 
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 594f051..8dec44e 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -510,8 +510,9 @@
   void Compare32BitValue(CpuRegister dest, int32_t value);
   void Compare64BitValue(CpuRegister dest, int64_t value);
 
-  // Compare int values. Supports only register locations for `lhs`.
+  // Compare int values. Supports register locations for `lhs`.
   void GenerateIntCompare(Location lhs, Location rhs);
+  void GenerateIntCompare(CpuRegister lhs, Location rhs);
 
   // Compare long values. Supports only register locations for `lhs`.
   void GenerateLongCompare(Location lhs, Location rhs);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index f21dc0e..af2fe9c 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -41,7 +41,7 @@
 #include "sharpening.h"
 #include "ssa_builder.h"
 #include "ssa_phi_elimination.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
@@ -1321,7 +1321,7 @@
   HConstantFolding fold(callee_graph);
   HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_);
   InstructionSimplifier simplify(callee_graph, stats_);
-  IntrinsicsRecognizer intrinsics(callee_graph, compiler_driver_, stats_);
+  IntrinsicsRecognizer intrinsics(callee_graph, stats_);
 
   HOptimization* optimizations[] = {
     &intrinsics,
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 3b08d9f..f7d67db 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -22,7 +22,7 @@
 #include "dex_instruction-inl.h"
 #include "driver/compiler_options.h"
 #include "imtable-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -675,7 +675,7 @@
 
   ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
   // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId
   // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache.
@@ -1284,7 +1284,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(compilation_unit.GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(compilation_unit.GetClassLoader())));
   Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
 
   return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
@@ -1303,7 +1303,7 @@
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
       soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
   Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
@@ -1344,7 +1344,7 @@
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   ArtField* resolved_field = compiler_driver_->ResolveField(
       soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true);
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index ff829af..3bb1c1d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,7 +18,7 @@
 
 #include "intrinsics.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 495f3fd..56e4c7a 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -44,6 +44,14 @@
   size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
   Primitive::Type type = instruction->GetType();
 
+  // TODO: Implement reading (length + compression) for String compression feature from
+  // negative offset (count_offset - data_offset). Thumb2Assembler does not support T4
+  // encoding of "LDR (immediate)" at the moment.
+  // Don't move array pointer if it is charAt because we need to take the count first.
+  if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+    return;
+  }
+
   if (type == Primitive::kPrimLong
       || type == Primitive::kPrimFloat
       || type == Primitive::kPrimDouble) {
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 6d107d5..d0dd650 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -140,6 +140,13 @@
 
 void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
   size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
+  // Don't move the array pointer if it is charAt because we need to take the count first.
+  // TODO: Implement reading (length + compression) for String compression feature from
+  // negative offset (count_offset - data_offset) using LDP and clobbering an extra temporary.
+  // Note that "LDR (Immediate)" does not have a "signed offset" encoding.
+  if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+    return;
+  }
   if (TryExtractArrayAccessAddress(instruction,
                                    instruction->GetArray(),
                                    instruction->GetIndex(),
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 4d4bbcf..412ccfc 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -18,14 +18,11 @@
 
 #include "art_method.h"
 #include "class_linker.h"
-#include "dex/quick/dex_file_method_inliner.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "invoke_type.h"
 #include "mirror/dex_cache-inl.h"
 #include "nodes.h"
-#include "quick/inline_method_analyser.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
@@ -36,7 +33,7 @@
   switch (i) {
     case Intrinsics::kNone:
       return kInterface;  // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
     case Intrinsics::k ## Name: \
       return IsStatic;
 #include "intrinsics_list.h"
@@ -52,7 +49,7 @@
   switch (i) {
     case Intrinsics::kNone:
       return kNeedsEnvironmentOrCache;  // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
     case Intrinsics::k ## Name: \
       return NeedsEnvironmentOrCache;
 #include "intrinsics_list.h"
@@ -68,7 +65,7 @@
   switch (i) {
     case Intrinsics::kNone:
       return kAllSideEffects;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
     case Intrinsics::k ## Name: \
       return SideEffects;
 #include "intrinsics_list.h"
@@ -84,7 +81,7 @@
   switch (i) {
     case Intrinsics::kNone:
       return kCanThrow;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
     case Intrinsics::k ## Name: \
       return Exceptions;
 #include "intrinsics_list.h"
@@ -95,430 +92,7 @@
   return kCanThrow;
 }
 
-static Primitive::Type GetType(uint64_t data, bool is_op_size) {
-  if (is_op_size) {
-    switch (static_cast<OpSize>(data)) {
-      case kSignedByte:
-        return Primitive::kPrimByte;
-      case kSignedHalf:
-        return Primitive::kPrimShort;
-      case k32:
-        return Primitive::kPrimInt;
-      case k64:
-        return Primitive::kPrimLong;
-      default:
-        LOG(FATAL) << "Unknown/unsupported op size " << data;
-        UNREACHABLE();
-    }
-  } else {
-    if ((data & kIntrinsicFlagIsLong) != 0) {
-      return Primitive::kPrimLong;
-    }
-    if ((data & kIntrinsicFlagIsObject) != 0) {
-      return Primitive::kPrimNot;
-    }
-    return Primitive::kPrimInt;
-  }
-}
-
-static Intrinsics GetIntrinsic(InlineMethod method) {
-  switch (method.opcode) {
-    // Floating-point conversions.
-    case kIntrinsicDoubleCvt:
-      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
-          Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
-    case kIntrinsicFloatCvt:
-      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
-          Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
-    case kIntrinsicFloat2Int:
-      return Intrinsics::kFloatFloatToIntBits;
-    case kIntrinsicDouble2Long:
-      return Intrinsics::kDoubleDoubleToLongBits;
-
-    // Floating-point tests.
-    case kIntrinsicFloatIsInfinite:
-      return Intrinsics::kFloatIsInfinite;
-    case kIntrinsicDoubleIsInfinite:
-      return Intrinsics::kDoubleIsInfinite;
-    case kIntrinsicFloatIsNaN:
-      return Intrinsics::kFloatIsNaN;
-    case kIntrinsicDoubleIsNaN:
-      return Intrinsics::kDoubleIsNaN;
-
-    // Bit manipulations.
-    case kIntrinsicReverseBits:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerReverse;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongReverse;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicReverseBytes:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimShort:
-          return Intrinsics::kShortReverseBytes;
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerReverseBytes;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongReverseBytes;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicRotateRight:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerRotateRight;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongRotateRight;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicRotateLeft:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerRotateLeft;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongRotateLeft;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-
-    // Misc data processing.
-    case kIntrinsicBitCount:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerBitCount;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongBitCount;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicCompare:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerCompare;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongCompare;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicHighestOneBit:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerHighestOneBit;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongHighestOneBit;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicLowestOneBit:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerLowestOneBit;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongLowestOneBit;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicNumberOfLeadingZeros:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerNumberOfLeadingZeros;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongNumberOfLeadingZeros;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicNumberOfTrailingZeros:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerNumberOfTrailingZeros;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongNumberOfTrailingZeros;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicSignum:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimInt:
-          return Intrinsics::kIntegerSignum;
-        case Primitive::kPrimLong:
-          return Intrinsics::kLongSignum;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-
-    // Abs.
-    case kIntrinsicAbsDouble:
-      return Intrinsics::kMathAbsDouble;
-    case kIntrinsicAbsFloat:
-      return Intrinsics::kMathAbsFloat;
-    case kIntrinsicAbsInt:
-      return Intrinsics::kMathAbsInt;
-    case kIntrinsicAbsLong:
-      return Intrinsics::kMathAbsLong;
-
-    // Min/max.
-    case kIntrinsicMinMaxDouble:
-      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
-          Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
-    case kIntrinsicMinMaxFloat:
-      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
-          Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
-    case kIntrinsicMinMaxInt:
-      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
-          Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
-    case kIntrinsicMinMaxLong:
-      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
-          Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
-
-    // More math builtins.
-    case kIntrinsicCos:
-      return Intrinsics::kMathCos;
-    case kIntrinsicSin:
-      return Intrinsics::kMathSin;
-    case kIntrinsicAcos:
-      return Intrinsics::kMathAcos;
-    case kIntrinsicAsin:
-      return Intrinsics::kMathAsin;
-    case kIntrinsicAtan:
-      return Intrinsics::kMathAtan;
-    case kIntrinsicAtan2:
-      return Intrinsics::kMathAtan2;
-    case kIntrinsicCbrt:
-      return Intrinsics::kMathCbrt;
-    case kIntrinsicCosh:
-      return Intrinsics::kMathCosh;
-    case kIntrinsicExp:
-      return Intrinsics::kMathExp;
-    case kIntrinsicExpm1:
-      return Intrinsics::kMathExpm1;
-    case kIntrinsicHypot:
-      return Intrinsics::kMathHypot;
-    case kIntrinsicLog:
-      return Intrinsics::kMathLog;
-    case kIntrinsicLog10:
-      return Intrinsics::kMathLog10;
-    case kIntrinsicNextAfter:
-      return Intrinsics::kMathNextAfter;
-    case kIntrinsicSinh:
-      return Intrinsics::kMathSinh;
-    case kIntrinsicTan:
-      return Intrinsics::kMathTan;
-    case kIntrinsicTanh:
-      return Intrinsics::kMathTanh;
-
-    // Misc math.
-    case kIntrinsicSqrt:
-      return Intrinsics::kMathSqrt;
-    case kIntrinsicCeil:
-      return Intrinsics::kMathCeil;
-    case kIntrinsicFloor:
-      return Intrinsics::kMathFloor;
-    case kIntrinsicRint:
-      return Intrinsics::kMathRint;
-    case kIntrinsicRoundDouble:
-      return Intrinsics::kMathRoundDouble;
-    case kIntrinsicRoundFloat:
-      return Intrinsics::kMathRoundFloat;
-
-    // System.arraycopy.
-    case kIntrinsicSystemArrayCopyCharArray:
-      return Intrinsics::kSystemArrayCopyChar;
-
-    case kIntrinsicSystemArrayCopy:
-      return Intrinsics::kSystemArrayCopy;
-
-    // Thread.currentThread.
-    case kIntrinsicCurrentThread:
-      return Intrinsics::kThreadCurrentThread;
-
-    // Memory.peek.
-    case kIntrinsicPeek:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimByte:
-          return Intrinsics::kMemoryPeekByte;
-        case Primitive::kPrimShort:
-          return Intrinsics::kMemoryPeekShortNative;
-        case Primitive::kPrimInt:
-          return Intrinsics::kMemoryPeekIntNative;
-        case Primitive::kPrimLong:
-          return Intrinsics::kMemoryPeekLongNative;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-
-    // Memory.poke.
-    case kIntrinsicPoke:
-      switch (GetType(method.d.data, true)) {
-        case Primitive::kPrimByte:
-          return Intrinsics::kMemoryPokeByte;
-        case Primitive::kPrimShort:
-          return Intrinsics::kMemoryPokeShortNative;
-        case Primitive::kPrimInt:
-          return Intrinsics::kMemoryPokeIntNative;
-        case Primitive::kPrimLong:
-          return Intrinsics::kMemoryPokeLongNative;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-
-    // String.
-    case kIntrinsicCharAt:
-      return Intrinsics::kStringCharAt;
-    case kIntrinsicCompareTo:
-      return Intrinsics::kStringCompareTo;
-    case kIntrinsicEquals:
-      return Intrinsics::kStringEquals;
-    case kIntrinsicGetCharsNoCheck:
-      return Intrinsics::kStringGetCharsNoCheck;
-    case kIntrinsicIsEmptyOrLength:
-      return ((method.d.data & kIntrinsicFlagIsEmpty) == 0) ?
-          Intrinsics::kStringLength : Intrinsics::kStringIsEmpty;
-    case kIntrinsicIndexOf:
-      return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
-          Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
-    case kIntrinsicNewStringFromBytes:
-      return Intrinsics::kStringNewStringFromBytes;
-    case kIntrinsicNewStringFromChars:
-      return Intrinsics::kStringNewStringFromChars;
-    case kIntrinsicNewStringFromString:
-      return Intrinsics::kStringNewStringFromString;
-
-    case kIntrinsicCas:
-      switch (GetType(method.d.data, false)) {
-        case Primitive::kPrimNot:
-          return Intrinsics::kUnsafeCASObject;
-        case Primitive::kPrimInt:
-          return Intrinsics::kUnsafeCASInt;
-        case Primitive::kPrimLong:
-          return Intrinsics::kUnsafeCASLong;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    case kIntrinsicUnsafeGet: {
-      const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
-      switch (GetType(method.d.data, false)) {
-        case Primitive::kPrimInt:
-          return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
-        case Primitive::kPrimLong:
-          return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
-        case Primitive::kPrimNot:
-          return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-    }
-    case kIntrinsicUnsafePut: {
-      enum Sync { kNoSync, kVolatile, kOrdered };
-      const Sync sync =
-          ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
-          ((method.d.data & kIntrinsicFlagIsOrdered) != 0)  ? kOrdered :
-                                                              kNoSync;
-      switch (GetType(method.d.data, false)) {
-        case Primitive::kPrimInt:
-          switch (sync) {
-            case kNoSync:
-              return Intrinsics::kUnsafePut;
-            case kVolatile:
-              return Intrinsics::kUnsafePutVolatile;
-            case kOrdered:
-              return Intrinsics::kUnsafePutOrdered;
-          }
-          break;
-        case Primitive::kPrimLong:
-          switch (sync) {
-            case kNoSync:
-              return Intrinsics::kUnsafePutLong;
-            case kVolatile:
-              return Intrinsics::kUnsafePutLongVolatile;
-            case kOrdered:
-              return Intrinsics::kUnsafePutLongOrdered;
-          }
-          break;
-        case Primitive::kPrimNot:
-          switch (sync) {
-            case kNoSync:
-              return Intrinsics::kUnsafePutObject;
-            case kVolatile:
-              return Intrinsics::kUnsafePutObjectVolatile;
-            case kOrdered:
-              return Intrinsics::kUnsafePutObjectOrdered;
-          }
-          break;
-        default:
-          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
-          UNREACHABLE();
-      }
-      break;
-    }
-
-    // 1.8.
-    case kIntrinsicUnsafeGetAndAddInt:
-      return Intrinsics::kUnsafeGetAndAddInt;
-    case kIntrinsicUnsafeGetAndAddLong:
-      return Intrinsics::kUnsafeGetAndAddLong;
-    case kIntrinsicUnsafeGetAndSetInt:
-      return Intrinsics::kUnsafeGetAndSetInt;
-    case kIntrinsicUnsafeGetAndSetLong:
-      return Intrinsics::kUnsafeGetAndSetLong;
-    case kIntrinsicUnsafeGetAndSetObject:
-      return Intrinsics::kUnsafeGetAndSetObject;
-    case kIntrinsicUnsafeLoadFence:
-      return Intrinsics::kUnsafeLoadFence;
-    case kIntrinsicUnsafeStoreFence:
-      return Intrinsics::kUnsafeStoreFence;
-    case kIntrinsicUnsafeFullFence:
-      return Intrinsics::kUnsafeFullFence;
-
-    // Virtual cases.
-
-    case kIntrinsicReferenceGetReferent:
-      return Intrinsics::kReferenceGetReferent;
-
-    // Quick inliner cases. Remove after refactoring. They are here so that we can use the
-    // compiler to warn on missing cases.
-
-    case kInlineOpNop:
-    case kInlineOpReturnArg:
-    case kInlineOpNonWideConst:
-    case kInlineOpIGet:
-    case kInlineOpIPut:
-    case kInlineOpConstructor:
-      return Intrinsics::kNone;
-
-    // String init cases, not intrinsics.
-
-    case kInlineStringInit:
-      return Intrinsics::kNone;
-
-    // No default case to make the compiler warn on missing cases.
-  }
-  return Intrinsics::kNone;
-}
-
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
-  // The DexFileMethodInliner should have checked whether the methods are agreeing with
-  // what we expect, i.e., static methods are called as such. Add another check here for
-  // our expectations:
-  //
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
   // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
   //
   // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
@@ -542,13 +116,9 @@
         return true;
       }
       if (invoke_type == kVirtual) {
-        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+        ArtMethod* art_method = invoke->GetResolvedMethod();
         ScopedObjectAccess soa(Thread::Current());
-        ArtMethod* art_method =
-            class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
-                invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
-        return art_method != nullptr &&
-            (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+        return (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
       }
       return false;
 
@@ -561,8 +131,8 @@
   }
 }
 
-// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
 void IntrinsicsRecognizer::Run() {
+  ScopedObjectAccess soa(Thread::Current());
   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
@@ -570,26 +140,20 @@
       HInstruction* inst = inst_it.Current();
       if (inst->IsInvoke()) {
         HInvoke* invoke = inst->AsInvoke();
-        InlineMethod method;
-        const DexFile& dex_file = invoke->GetDexFile();
-        DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
-        DCHECK(inliner != nullptr);
-        if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
-          Intrinsics intrinsic = GetIntrinsic(method);
-
-          if (intrinsic != Intrinsics::kNone) {
-            if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
-              LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
-                  << intrinsic << " for "
-                  << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
-                  << invoke->DebugName();
-            } else {
-              invoke->SetIntrinsic(intrinsic,
-                                   NeedsEnvironmentOrCache(intrinsic),
-                                   GetSideEffects(intrinsic),
-                                   GetExceptions(intrinsic));
-              MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
-            }
+        ArtMethod* art_method = invoke->GetResolvedMethod();
+        if (art_method != nullptr && art_method->IsIntrinsic()) {
+          Intrinsics intrinsic = static_cast<Intrinsics>(art_method->GetIntrinsic());
+          if (!CheckInvokeType(intrinsic, invoke)) {
+            LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
+                << intrinsic << " for "
+                << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+                << invoke->DebugName();
+          } else {
+            invoke->SetIntrinsic(intrinsic,
+                                 NeedsEnvironmentOrCache(intrinsic),
+                                 GetSideEffects(intrinsic),
+                                 GetExceptions(intrinsic));
+            MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
           }
         }
       }
@@ -602,7 +166,7 @@
     case Intrinsics::kNone:
       os << "None";
       break;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
     case Intrinsics::k ## Name: \
       os << # Name; \
       break;
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 62f731d..1e73cf6 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -34,17 +34,14 @@
 // Recognize intrinsics from HInvoke nodes.
 class IntrinsicsRecognizer : public HOptimization {
  public:
-  IntrinsicsRecognizer(HGraph* graph, CompilerDriver* driver, OptimizingCompilerStats* stats)
-      : HOptimization(graph, kIntrinsicsRecognizerPassName, stats),
-        driver_(driver) {}
+  IntrinsicsRecognizer(HGraph* graph, OptimizingCompilerStats* stats)
+      : HOptimization(graph, kIntrinsicsRecognizerPassName, stats) {}
 
   void Run() OVERRIDE;
 
   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
 
  private:
-  CompilerDriver* driver_;
-
   DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
 };
 
@@ -58,7 +55,7 @@
     switch (invoke->GetIntrinsic()) {
       case Intrinsics::kNone:
         return;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, ...) \
       case Intrinsics::k ## Name: \
         Visit ## Name(invoke);    \
         return;
@@ -73,7 +70,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, ...) \
   virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
   }
 #include "intrinsics_list.h"
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index fd2da10..96a6ecb 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1039,6 +1039,11 @@
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
+  // Need temporary registers for String compression's feature.
+  if (mirror::kUseStringCompression) {
+    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());
+  }
   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
 }
 
@@ -1053,10 +1058,16 @@
   Register temp0 = locations->GetTemp(0).AsRegister<Register>();
   Register temp1 = locations->GetTemp(1).AsRegister<Register>();
   Register temp2 = locations->GetTemp(2).AsRegister<Register>();
+  Register temp3, temp4;
+  if (mirror::kUseStringCompression) {
+    temp3 = locations->GetTemp(3).AsRegister<Register>();
+    temp4 = locations->GetTemp(4).AsRegister<Register>();
+  }
 
   Label loop;
   Label find_char_diff;
   Label end;
+  Label different_compression;
 
   // Get offsets of count and value fields within a string object.
   const int32_t count_offset = mirror::String::CountOffset().Int32Value();
@@ -1077,20 +1088,40 @@
   // Reference equality check, return 0 if same reference.
   __ subs(out, str, ShifterOperand(arg));
   __ b(&end, EQ);
-  // Load lengths of this and argument strings.
-  __ ldr(temp2, Address(str, count_offset));
-  __ ldr(temp1, Address(arg, count_offset));
+  if (mirror::kUseStringCompression) {
+    // Load lengths of this and argument strings.
+    __ ldr(temp3, Address(str, count_offset));
+    __ ldr(temp4, Address(arg, count_offset));
+    // Clean out compression flag from lengths.
+    __ bic(temp0, temp3, ShifterOperand(0x80000000));
+    __ bic(IP, temp4, ShifterOperand(0x80000000));
+  } else {
+    // Load lengths of this and argument strings.
+    __ ldr(temp0, Address(str, count_offset));
+    __ ldr(IP, Address(arg, count_offset));
+  }
   // out = length diff.
-  __ subs(out, temp2, ShifterOperand(temp1));
+  __ subs(out, temp0, ShifterOperand(IP));
   // temp0 = min(len(str), len(arg)).
-  __ it(Condition::LT, kItElse);
-  __ mov(temp0, ShifterOperand(temp2), Condition::LT);
-  __ mov(temp0, ShifterOperand(temp1), Condition::GE);
+  __ it(GT);
+  __ mov(temp0, ShifterOperand(IP), GT);
   // Shorter string is empty?
   __ CompareAndBranchIfZero(temp0, &end);
 
+  if (mirror::kUseStringCompression) {
+    // Check if both strings using same compression style to use this comparison loop.
+    __ eors(temp3, temp3, ShifterOperand(temp4));
+    __ b(&different_compression, MI);
+  }
   // Store offset of string value in preparation for comparison loop.
   __ mov(temp1, ShifterOperand(value_offset));
+  if (mirror::kUseStringCompression) {
+    // For string compression, calculate the number of bytes to compare (not chars).
+    // This could in theory exceed INT32_MAX, so treat temp0 as unsigned.
+    __ cmp(temp4, ShifterOperand(0));
+    __ it(GE);
+    __ add(temp0, temp0, ShifterOperand(temp0), GE);
+  }
 
   // Assertions that must hold in order to compare multiple characters at a time.
   CHECK_ALIGNED(value_offset, 8);
@@ -1100,6 +1131,7 @@
   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
   DCHECK_EQ(char_size, 2u);
 
+  Label find_char_diff_2nd_cmp;
   // Unrolled loop comparing 4x16-bit chars per iteration (ok because of string data alignment).
   __ Bind(&loop);
   __ ldr(IP, Address(str, temp1));
@@ -1107,43 +1139,113 @@
   __ cmp(IP, ShifterOperand(temp2));
   __ b(&find_char_diff, NE);
   __ add(temp1, temp1, ShifterOperand(char_size * 2));
-  __ sub(temp0, temp0, ShifterOperand(2));
 
   __ ldr(IP, Address(str, temp1));
   __ ldr(temp2, Address(arg, temp1));
   __ cmp(IP, ShifterOperand(temp2));
-  __ b(&find_char_diff, NE);
+  __ b(&find_char_diff_2nd_cmp, NE);
   __ add(temp1, temp1, ShifterOperand(char_size * 2));
-  __ subs(temp0, temp0, ShifterOperand(2));
-
-  __ b(&loop, GT);
+  // With string compression, we have compared 8 bytes, otherwise 4 chars.
+  __ subs(temp0, temp0, ShifterOperand(mirror::kUseStringCompression ? 8 : 4));
+  __ b(&loop, HI);
   __ b(&end);
 
-  // Find the single 16-bit character difference.
+  __ Bind(&find_char_diff_2nd_cmp);
+  if (mirror::kUseStringCompression) {
+    __ subs(temp0, temp0, ShifterOperand(4));  // 4 bytes previously compared.
+    __ b(&end, LS);  // Was the second comparison fully beyond the end?
+  } else {
+    // Without string compression, we can start treating temp0 as signed
+    // and rely on the signed comparison below.
+    __ sub(temp0, temp0, ShifterOperand(2));
+  }
+
+  // Find the single character difference.
   __ Bind(&find_char_diff);
   // Get the bit position of the first character that differs.
   __ eor(temp1, temp2, ShifterOperand(IP));
   __ rbit(temp1, temp1);
   __ clz(temp1, temp1);
 
-  // temp0 = number of 16-bit characters remaining to compare.
-  // (it could be < 1 if a difference is found after the first SUB in the comparison loop, and
-  // after the end of the shorter string data).
+  // temp0 = number of characters remaining to compare.
+  // (Without string compression, it could be < 1 if a difference is found by the second CMP
+  // in the comparison loop, and after the end of the shorter string data).
 
-  // (temp1 >> 4) = character where difference occurs between the last two words compared, on the
-  // interval [0,1] (0 for low half-word different, 1 for high half-word different).
+  // Without string compression (temp1 >> 4) = character where difference occurs between the last
+  // two words compared, in the interval [0,1].
+  // (0 for low half-word different, 1 for high half-word different).
+  // With string compression, (temp1 << 3) = byte where the difference occurs,
+  // in the interval [0,3].
 
-  // If temp0 <= (temp1 >> 4), the difference occurs outside the remaining string data, so just
-  // return length diff (out).
-  __ cmp(temp0, ShifterOperand(temp1, LSR, 4));
-  __ b(&end, LE);
+  // If temp0 <= (temp1 >> (kUseStringCompression ? 3 : 4)), the difference occurs outside
+  // the remaining string data, so just return length diff (out).
+  // The comparison is unsigned for string compression, otherwise signed.
+  __ cmp(temp0, ShifterOperand(temp1, LSR, mirror::kUseStringCompression ? 3 : 4));
+  __ b(&end, mirror::kUseStringCompression ? LS : LE);
   // Extract the characters and calculate the difference.
+  Label uncompressed_string, continue_process;
+  if (mirror::kUseStringCompression) {
+    __ cmp(temp4, ShifterOperand(0));
+    __ b(&uncompressed_string, GE);
+    __ bic(temp1, temp1, ShifterOperand(0x7));
+    __ b(&continue_process);
+  }
+  __ Bind(&uncompressed_string);
   __ bic(temp1, temp1, ShifterOperand(0xf));
+  __ Bind(&continue_process);
+
   __ Lsr(temp2, temp2, temp1);
   __ Lsr(IP, IP, temp1);
+  Label calculate_difference, uncompressed_string_extract_chars;
+  if (mirror::kUseStringCompression) {
+    __ cmp(temp4, ShifterOperand(0));
+    __ b(&uncompressed_string_extract_chars, GE);
+    __ ubfx(temp2, temp2, 0, 8);
+    __ ubfx(IP, IP, 0, 8);
+    __ b(&calculate_difference);
+  }
+  __ Bind(&uncompressed_string_extract_chars);
   __ movt(temp2, 0);
   __ movt(IP, 0);
+  __ Bind(&calculate_difference);
   __ sub(out, IP, ShifterOperand(temp2));
+  __ b(&end);
+
+  if (mirror::kUseStringCompression) {
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    Label loop_arg_compressed, loop_this_compressed, find_diff;
+    // Comparison for different compression style.
+    // This part is when THIS is compressed and ARG is not.
+    __ Bind(&different_compression);
+    __ add(temp2, str, ShifterOperand(value_offset));
+    __ add(temp3, arg, ShifterOperand(value_offset));
+    __ cmp(temp4, ShifterOperand(0));
+    __ b(&loop_arg_compressed, LT);
+
+    __ Bind(&loop_this_compressed);
+    __ ldrb(IP, Address(temp2, c_char_size, Address::PostIndex));
+    __ ldrh(temp4, Address(temp3, char_size, Address::PostIndex));
+    __ cmp(IP, ShifterOperand(temp4));
+    __ b(&find_diff, NE);
+    __ subs(temp0, temp0, ShifterOperand(1));
+    __ b(&loop_this_compressed, GT);
+    __ b(&end);
+
+    // This part is when THIS is not compressed and ARG is.
+    __ Bind(&loop_arg_compressed);
+    __ ldrh(IP, Address(temp2, char_size, Address::PostIndex));
+    __ ldrb(temp4, Address(temp3, c_char_size, Address::PostIndex));
+    __ cmp(IP, ShifterOperand(temp4));
+    __ b(&find_diff, NE);
+    __ subs(temp0, temp0, ShifterOperand(1));
+    __ b(&loop_arg_compressed, GT);
+    __ b(&end);
+
+    // Calculate the difference.
+    __ Bind(&find_diff);
+    __ sub(out, IP, ShifterOperand(temp4));
+  }
 
   __ Bind(&end);
 
@@ -1180,7 +1282,7 @@
   Register temp1 = locations->GetTemp(1).AsRegister<Register>();
   Register temp2 = locations->GetTemp(2).AsRegister<Register>();
 
-  Label loop;
+  Label loop, preloop;
   Label end;
   Label return_true;
   Label return_false;
@@ -1214,11 +1316,15 @@
   __ ldr(temp, Address(str, count_offset));
   __ ldr(temp1, Address(arg, count_offset));
   // Check if lengths are equal, return false if they're not.
+  // Also compares the compression style, if differs return false.
   __ cmp(temp, ShifterOperand(temp1));
   __ b(&return_false, NE);
   // Return true if both strings are empty.
+  if (mirror::kUseStringCompression) {
+    // Length needs to be masked out first because 0 is treated as compressed.
+    __ bic(temp, temp, ShifterOperand(0x80000000));
+  }
   __ cbz(temp, &return_true);
-
   // Reference equality check, return true if same reference.
   __ cmp(str, ShifterOperand(arg));
   __ b(&return_true, EQ);
@@ -1227,10 +1333,19 @@
   DCHECK_ALIGNED(value_offset, 4);
   static_assert(IsAligned<4>(kObjectAlignment), "String data must be aligned for fast compare.");
 
-  __ LoadImmediate(temp1, value_offset);
-
+  if (mirror::kUseStringCompression) {
+    // If not compressed, directly to fast compare. Else do preprocess on length.
+    __ cmp(temp1, ShifterOperand(0));
+    __ b(&preloop, GT);
+    // Mask out compression flag and adjust length for compressed string (8-bit)
+    // as if it is a 16-bit data, new_length = (length + 1) / 2.
+    __ add(temp, temp, ShifterOperand(1));
+    __ Lsr(temp, temp, 1);
+    __ Bind(&preloop);
+  }
   // Loop to compare strings 2 characters at a time starting at the front of the string.
   // Ok to do this because strings with an odd length are zero-padded.
+  __ LoadImmediate(temp1, value_offset);
   __ Bind(&loop);
   __ ldr(out, Address(str, temp1));
   __ ldr(temp2, Address(arg, temp1));
@@ -2330,22 +2445,31 @@
   Register src_ptr = locations->GetTemp(1).AsRegister<Register>();
   Register dst_ptr = locations->GetTemp(2).AsRegister<Register>();
 
-  // src range to copy.
-  __ add(src_ptr, srcObj, ShifterOperand(value_offset));
-  __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1));
-
+  Label done, compressed_string_loop;
   // dst to be copied.
   __ add(dst_ptr, dstObj, ShifterOperand(data_offset));
   __ add(dst_ptr, dst_ptr, ShifterOperand(dstBegin, LSL, 1));
 
   __ subs(num_chr, srcEnd, ShifterOperand(srcBegin));
-
-  // Do the copy.
-  Label loop, remainder, done;
-
   // Early out for valid zero-length retrievals.
   __ b(&done, EQ);
 
+  // src range to copy.
+  __ add(src_ptr, srcObj, ShifterOperand(value_offset));
+  Label compressed_string_preloop;
+  if (mirror::kUseStringCompression) {
+    // Location of count in string.
+    const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+    // String's length.
+    __ ldr(IP, Address(srcObj, count_offset));
+    __ cmp(IP, ShifterOperand(0));
+    __ b(&compressed_string_preloop, LT);
+  }
+  __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1));
+
+  // Do the copy.
+  Label loop, remainder;
+
   // Save repairing the value of num_chr on the < 4 character path.
   __ subs(IP, num_chr, ShifterOperand(4));
   __ b(&remainder, LT);
@@ -2374,6 +2498,20 @@
   __ subs(num_chr, num_chr, ShifterOperand(1));
   __ strh(IP, Address(dst_ptr, char_size, Address::PostIndex));
   __ b(&remainder, GT);
+  __ b(&done);
+
+  if (mirror::kUseStringCompression) {
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
+    __ Bind(&compressed_string_preloop);
+    __ add(src_ptr, src_ptr, ShifterOperand(srcBegin));
+    __ Bind(&compressed_string_loop);
+    __ ldrb(IP, Address(src_ptr, c_char_size, Address::PostIndex));
+    __ strh(IP, Address(dst_ptr, char_size, Address::PostIndex));
+    __ subs(num_chr, num_chr, ShifterOperand(1));
+    __ b(&compressed_string_loop, GT);
+  }
 
   __ Bind(&done);
 }
diff --git a/compiler/optimizing/intrinsics_arm.h b/compiler/optimizing/intrinsics_arm.h
index c671700..7f20ea4 100644
--- a/compiler/optimizing/intrinsics_arm.h
+++ b/compiler/optimizing/intrinsics_arm.h
@@ -37,7 +37,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -64,7 +64,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index ce58657..e2c1802 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1223,6 +1223,11 @@
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
+  // Need temporary registers for String compression's feature.
+  if (mirror::kUseStringCompression) {
+    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());
+  }
   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
 }
 
@@ -1239,10 +1244,16 @@
   Register temp0 = WRegisterFrom(locations->GetTemp(0));
   Register temp1 = WRegisterFrom(locations->GetTemp(1));
   Register temp2 = WRegisterFrom(locations->GetTemp(2));
+  Register temp3, temp5;
+  if (mirror::kUseStringCompression) {
+    temp3 = WRegisterFrom(locations->GetTemp(3));
+    temp5 = WRegisterFrom(locations->GetTemp(4));
+  }
 
   vixl::aarch64::Label loop;
   vixl::aarch64::Label find_char_diff;
   vixl::aarch64::Label end;
+  vixl::aarch64::Label different_compression;
 
   // Get offsets of count and value fields within a string object.
   const int32_t count_offset = mirror::String::CountOffset().Int32Value();
@@ -1263,9 +1274,18 @@
   // Reference equality check, return 0 if same reference.
   __ Subs(out, str, arg);
   __ B(&end, eq);
-  // Load lengths of this and argument strings.
-  __ Ldr(temp0, HeapOperand(str, count_offset));
-  __ Ldr(temp1, HeapOperand(arg, count_offset));
+  if (mirror::kUseStringCompression) {
+    // Load lengths of this and argument strings.
+    __ Ldr(temp3, HeapOperand(str, count_offset));
+    __ Ldr(temp5, HeapOperand(arg, count_offset));
+    // Clean out compression flag from lengths.
+    __ Bic(temp0, temp3, Operand(static_cast<int32_t>(0x80000000)));
+    __ Bic(temp1, temp5, Operand(static_cast<int32_t>(0x80000000)));
+  } else {
+    // Load lengths of this and argument strings.
+    __ Ldr(temp0, HeapOperand(str, count_offset));
+    __ Ldr(temp1, HeapOperand(arg, count_offset));
+  }
   // Return zero if both strings are empty.
   __ Orr(out, temp0, temp1);
   __ Cbz(out, &end);
@@ -1276,8 +1296,22 @@
   // Shorter string is empty?
   __ Cbz(temp2, &end);
 
+  if (mirror::kUseStringCompression) {
+    // Check if both strings using same compression style to use this comparison loop.
+    __ Eor(temp3.W(), temp3, Operand(temp5));
+    __ Tbnz(temp3.W(), kWRegSize - 1, &different_compression);
+  }
   // Store offset of string value in preparation for comparison loop.
   __ Mov(temp1, value_offset);
+  if (mirror::kUseStringCompression) {
+    // For string compression, calculate the number of bytes to compare (not chars).
+    // This could be in theory exceed INT32_MAX, so treat temp2 as unsigned.
+    vixl::aarch64::Label let_it_signed;
+    __ Cmp(temp5, Operand(0));
+    __ B(lt, &let_it_signed);
+    __ Add(temp2, temp2, Operand(temp2));
+    __ Bind(&let_it_signed);
+  }
 
   UseScratchRegisterScope scratch_scope(masm);
   Register temp4 = scratch_scope.AcquireX();
@@ -1299,29 +1333,90 @@
   __ Cmp(temp4, temp0);
   __ B(ne, &find_char_diff);
   __ Add(temp1, temp1, char_size * 4);
-  __ Subs(temp2, temp2, 4);
-  __ B(gt, &loop);
+  // With string compression, we have compared 8 bytes, otherwise 4 chars.
+  __ Subs(temp2, temp2, (mirror::kUseStringCompression) ? 8 : 4);
+  __ B(hi, &loop);
   __ B(&end);
 
   // Promote temp1 to an X reg, ready for EOR.
   temp1 = temp1.X();
 
-  // Find the single 16-bit character difference.
+  // Find the single character difference.
   __ Bind(&find_char_diff);
   // Get the bit position of the first character that differs.
   __ Eor(temp1, temp0, temp4);
   __ Rbit(temp1, temp1);
   __ Clz(temp1, temp1);
-  // If the number of 16-bit chars remaining <= the index where the difference occurs (0-3), then
+  // If the number of chars remaining <= the index where the difference occurs (0-3), then
   // the difference occurs outside the remaining string data, so just return length diff (out).
-  __ Cmp(temp2, Operand(temp1.W(), LSR, 4));
-  __ B(le, &end);
+  // Unlike ARM, we're doing the comparison in one go here, without the subtraction at the
+  // find_char_diff_2nd_cmp path, so it doesn't matter whether the comparison is signed or
+  // unsigned when string compression is disabled.
+  // When it's enabled, the comparison must be unsigned.
+  __ Cmp(temp2, Operand(temp1.W(), LSR, (mirror::kUseStringCompression) ? 3 : 4));
+  __ B(ls, &end);
   // Extract the characters and calculate the difference.
+  vixl::aarch64::Label uncompressed_string, continue_process;
+  if (mirror:: kUseStringCompression) {
+    __ Tbz(temp5, kWRegSize - 1, &uncompressed_string);
+    __ Bic(temp1, temp1, 0x7);
+    __ B(&continue_process);
+  }
+  __ Bind(&uncompressed_string);
   __ Bic(temp1, temp1, 0xf);
+  __ Bind(&continue_process);
+
   __ Lsr(temp0, temp0, temp1);
   __ Lsr(temp4, temp4, temp1);
+  vixl::aarch64::Label uncompressed_string_extract_chars;
+  if (mirror::kUseStringCompression) {
+    __ Tbz(temp5, kWRegSize - 1, &uncompressed_string_extract_chars);
+    __ And(temp4, temp4, 0xff);
+    __ Sub(out, temp4.W(), Operand(temp0.W(), UXTB));
+    __ B(&end);
+  }
+  __ Bind(&uncompressed_string_extract_chars);
   __ And(temp4, temp4, 0xffff);
   __ Sub(out, temp4.W(), Operand(temp0.W(), UXTH));
+  __ B(&end);
+
+  if (mirror::kUseStringCompression) {
+    vixl::aarch64::Label loop_this_compressed, loop_arg_compressed, find_diff;
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    temp0 = temp0.W();
+    temp1 = temp1.W();
+    // Comparison for different compression style.
+    // This part is when THIS is compressed and ARG is not.
+    __ Bind(&different_compression);
+    __ Add(temp0, str, Operand(value_offset));
+    __ Add(temp1, arg, Operand(value_offset));
+    __ Cmp(temp5, Operand(0));
+    __ B(lt, &loop_arg_compressed);
+
+    __ Bind(&loop_this_compressed);
+    __ Ldrb(temp3, MemOperand(temp0.X(), c_char_size, PostIndex));
+    __ Ldrh(temp5, MemOperand(temp1.X(), char_size, PostIndex));
+    __ Cmp(temp3, Operand(temp5));
+    __ B(ne, &find_diff);
+    __ Subs(temp2, temp2, 1);
+    __ B(gt, &loop_this_compressed);
+    __ B(&end);
+
+    // This part is when THIS is not compressed and ARG is.
+    __ Bind(&loop_arg_compressed);
+    __ Ldrh(temp3, MemOperand(temp0.X(), char_size, PostIndex));
+    __ Ldrb(temp5, MemOperand(temp1.X(), c_char_size, PostIndex));
+    __ Cmp(temp3, Operand(temp5));
+    __ B(ne, &find_diff);
+    __ Subs(temp2, temp2, 1);
+    __ B(gt, &loop_arg_compressed);
+    __ B(&end);
+
+    // Calculate the difference.
+    __ Bind(&find_diff);
+    __ Sub(out, temp3.W(), Operand(temp5.W(), UXTH));
+  }
 
   __ Bind(&end);
 
@@ -1356,7 +1451,7 @@
   Register temp1 = WRegisterFrom(locations->GetTemp(0));
   Register temp2 = WRegisterFrom(locations->GetTemp(1));
 
-  vixl::aarch64::Label loop;
+  vixl::aarch64::Label loop, preloop;
   vixl::aarch64::Label end;
   vixl::aarch64::Label return_true;
   vixl::aarch64::Label return_false;
@@ -1394,22 +1489,37 @@
   __ Ldr(temp, MemOperand(str.X(), count_offset));
   __ Ldr(temp1, MemOperand(arg.X(), count_offset));
   // Check if lengths are equal, return false if they're not.
+  // Also compares the compression style, if differs return false.
   __ Cmp(temp, temp1);
   __ B(&return_false, ne);
-  // Store offset of string value in preparation for comparison loop
-  __ Mov(temp1, value_offset);
   // Return true if both strings are empty.
+  if (mirror::kUseStringCompression) {
+    // Length needs to be masked out first because 0 is treated as compressed.
+    __ Bic(temp, temp, Operand(static_cast<int32_t>(0x80000000)));
+  }
   __ Cbz(temp, &return_true);
 
   // Assertions that must hold in order to compare strings 4 characters at a time.
   DCHECK_ALIGNED(value_offset, 8);
   static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
 
+  if (mirror::kUseStringCompression) {
+    // If not compressed, directly to fast compare. Else do preprocess on length.
+    __ Cmp(temp1, Operand(0));
+    __ B(&preloop, gt);
+    // Mask out compression flag and adjust length for compressed string (8-bit)
+    // as if it is a 16-bit data, new_length = (length + 1) / 2
+    __ Add(temp, temp, 1);
+    __ Lsr(temp, temp, 1);
+  }
+
   temp1 = temp1.X();
   temp2 = temp2.X();
-
   // Loop to compare strings 4 characters at a time starting at the beginning of the string.
   // Ok to do this because strings are zero-padded to be 8-byte aligned.
+  // Store offset of string value in preparation for comparison loop
+  __ Bind(&preloop);
+  __ Mov(temp1, value_offset);
   __ Bind(&loop);
   __ Ldr(out, MemOperand(str.X(), temp1));
   __ Ldr(temp2, MemOperand(arg.X(), temp1));
@@ -1773,6 +1883,10 @@
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
   locations->AddTemp(Location::RequiresRegister());
+  // Need temporary register for String compression feature.
+  if (mirror::kUseStringCompression) {
+    locations->AddTemp(Location::RequiresRegister());
+  }
 }
 
 void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
@@ -1800,29 +1914,41 @@
   Register src_ptr = XRegisterFrom(locations->GetTemp(0));
   Register num_chr = XRegisterFrom(locations->GetTemp(1));
   Register tmp1 = XRegisterFrom(locations->GetTemp(2));
+  Register tmp3;
+  if (mirror::kUseStringCompression) {
+    tmp3 = WRegisterFrom(locations->GetTemp(3));
+  }
 
   UseScratchRegisterScope temps(masm);
   Register dst_ptr = temps.AcquireX();
   Register tmp2 = temps.AcquireX();
 
-  // src address to copy from.
-  __ Add(src_ptr, srcObj, Operand(value_offset));
-  __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1));
+  vixl::aarch64::Label done;
+  vixl::aarch64::Label compressed_string_loop;
+  __ Sub(num_chr, srcEnd, srcBegin);
+  // Early out for valid zero-length retrievals.
+  __ Cbz(num_chr, &done);
 
   // dst address start to copy to.
   __ Add(dst_ptr, dstObj, Operand(data_offset));
   __ Add(dst_ptr, dst_ptr, Operand(dstBegin, LSL, 1));
 
-  __ Sub(num_chr, srcEnd, srcBegin);
+  // src address to copy from.
+  __ Add(src_ptr, srcObj, Operand(value_offset));
+  vixl::aarch64::Label compressed_string_preloop;
+  if (mirror::kUseStringCompression) {
+    // Location of count in string.
+    const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+    // String's length.
+    __ Ldr(tmp3, MemOperand(srcObj, count_offset));
+    __ Tbnz(tmp3, kWRegSize - 1, &compressed_string_preloop);
+  }
+  __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1));
 
   // Do the copy.
   vixl::aarch64::Label loop;
-  vixl::aarch64::Label done;
   vixl::aarch64::Label remainder;
 
-  // Early out for valid zero-length retrievals.
-  __ Cbz(num_chr, &done);
-
   // Save repairing the value of num_chr on the < 8 character path.
   __ Subs(tmp1, num_chr, 8);
   __ B(lt, &remainder);
@@ -1848,6 +1974,20 @@
   __ Subs(num_chr, num_chr, 1);
   __ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
   __ B(gt, &remainder);
+  __ B(&done);
+
+  if (mirror::kUseStringCompression) {
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    __ Bind(&compressed_string_preloop);
+    __ Add(src_ptr, src_ptr, Operand(srcBegin));
+    // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
+    __ Bind(&compressed_string_loop);
+    __ Ldrb(tmp1, MemOperand(src_ptr, c_char_size, PostIndex));
+    __ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
+    __ Subs(num_chr, num_chr, Operand(1));
+    __ B(gt, &compressed_string_loop);
+  }
 
   __ Bind(&done);
 }
diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h
index 5251536..28e41cb 100644
--- a/compiler/optimizing/intrinsics_arm64.h
+++ b/compiler/optimizing/intrinsics_arm64.h
@@ -42,7 +42,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -66,7 +66,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
deleted file mode 100644
index db60238..0000000
--- a/compiler/optimizing/intrinsics_list.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-#define ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-
-// All intrinsics supported by the optimizing compiler. Format is name, then whether it is expected
-// to be a HInvokeStaticOrDirect node (compared to HInvokeVirtual), then whether it requires an
-// environment, may have side effects, or may throw exceptions.
-
-#define INTRINSICS_LIST(V) \
-  V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(FloatFloatToIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathCos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathSin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAcos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAsin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAtan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathAtan2, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathCbrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathCosh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathExp, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathExpm1, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathHypot, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathLog, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathLog10, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathSinh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathTan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathTanh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathSqrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathCeil, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathFloor, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathRint, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
-  V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
-  V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
-  V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
-  V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
-  V(StringCharAt, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringCompareTo, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringEquals, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
-  V(StringIsEmpty, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \
-  V(StringLength, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \
-  V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeCASInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeCASLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeCASObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGet, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePut, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetAndAddInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetAndAddLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetAndSetInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetAndSetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeGetAndSetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeLoadFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeStoreFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(UnsafeFullFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
-  V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow)
-
-#endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-#undef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_   // #define is only for lint.
diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h
index 575a7d0..e134cb8 100644
--- a/compiler/optimizing/intrinsics_mips.h
+++ b/compiler/optimizing/intrinsics_mips.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h
index 4137fbd..5b95c26 100644
--- a/compiler/optimizing/intrinsics_mips64.h
+++ b/compiler/optimizing/intrinsics_mips64.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index e61aba0..f41e4d9 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1401,23 +1401,39 @@
   __ cmpl(str, arg);
   __ j(kEqual, &return_true);
 
-  // Load length of receiver string.
+  // Load length and compression flag of receiver string.
   __ movl(ecx, Address(str, count_offset));
-  // Check if lengths are equal, return false if they're not.
+  // Check if lengths and compression flags are equal, return false if they're not.
+  // Two identical strings will always have same compression style since
+  // compression style is decided on alloc.
   __ cmpl(ecx, Address(arg, count_offset));
   __ j(kNotEqual, &return_false);
-  // Return true if both strings are empty.
-  __ jecxz(&return_true);
 
+  if (mirror::kUseStringCompression) {
+    NearLabel string_uncompressed;
+    // Differ cases into both compressed or both uncompressed. Different compression style
+    // is cut above.
+    __ cmpl(ecx, Immediate(0));
+    __ j(kGreaterEqual, &string_uncompressed);
+    // Divide string length by 2, rounding up, and continue as if uncompressed.
+    // Merge clearing the compression flag (+0x80000000) with +1 for rounding.
+    __ addl(ecx, Immediate(0x80000001));
+    __ shrl(ecx, Immediate(1));
+    __ Bind(&string_uncompressed);
+  }
+  // Return true if strings are empty.
+  __ jecxz(&return_true);
   // Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
   __ leal(esi, Address(str, value_offset));
   __ leal(edi, Address(arg, value_offset));
 
-  // Divide string length by 2 to compare characters 2 at a time and adjust for odd lengths.
+  // Divide string length by 2 to compare characters 2 at a time and adjust for lengths not
+  // divisible by 2.
   __ addl(ecx, Immediate(1));
   __ shrl(ecx, Immediate(1));
 
-  // Assertions that must hold in order to compare strings 2 characters at a time.
+  // Assertions that must hold in order to compare strings 2 characters (uncompressed)
+  // or 4 characters (compressed) at a time.
   DCHECK_ALIGNED(value_offset, 4);
   static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
 
@@ -1461,6 +1477,10 @@
   locations->AddTemp(Location::RegisterLocation(ECX));
   // Need another temporary to be able to compute the result.
   locations->AddTemp(Location::RequiresRegister());
+  if (mirror::kUseStringCompression) {
+    // Need another temporary to be able to save unflagged string length.
+    locations->AddTemp(Location::RequiresRegister());
+  }
 }
 
 static void GenerateStringIndexOf(HInvoke* invoke,
@@ -1478,6 +1498,8 @@
   Register counter = locations->GetTemp(0).AsRegister<Register>();
   Register string_length = locations->GetTemp(1).AsRegister<Register>();
   Register out = locations->Out().AsRegister<Register>();
+  // Only used when string compression feature is on.
+  Register string_length_flagged;
 
   // Check our assumptions for registers.
   DCHECK_EQ(string_obj, EDI);
@@ -1515,6 +1537,12 @@
 
   // Load string length, i.e., the count field of the string.
   __ movl(string_length, Address(string_obj, count_offset));
+  if (mirror::kUseStringCompression) {
+    string_length_flagged = locations->GetTemp(2).AsRegister<Register>();
+    __ movl(string_length_flagged, string_length);
+    // Mask out first bit used as compression flag.
+    __ andl(string_length, Immediate(INT32_MAX));
+  }
 
   // Do a zero-length check.
   // TODO: Support jecxz.
@@ -1540,20 +1568,50 @@
     __ cmpl(start_index, Immediate(0));
     __ cmovl(kGreater, counter, start_index);
 
-    // Move to the start of the string: string_obj + value_offset + 2 * start_index.
-    __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+    if (mirror::kUseStringCompression) {
+      NearLabel modify_counter, offset_uncompressed_label;
+      __ cmpl(string_length_flagged, Immediate(0));
+      __ j(kGreaterEqual, &offset_uncompressed_label);
+      // Move to the start of the string: string_obj + value_offset + start_index.
+      __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+      __ jmp(&modify_counter);
 
-    // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
-    // compare.
+      // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+      __ Bind(&offset_uncompressed_label);
+      __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+
+      // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
+      // compare.
+      __ Bind(&modify_counter);
+    } else {
+      __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+    }
     __ negl(counter);
     __ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
   }
 
-  // Everything is set up for repne scasw:
-  //   * Comparison address in EDI.
-  //   * Counter in ECX.
-  __ repne_scasw();
+  if (mirror::kUseStringCompression) {
+    NearLabel uncompressed_string_comparison;
+    NearLabel comparison_done;
+    __ cmpl(string_length_flagged, Immediate(0));
+    __ j(kGreater, &uncompressed_string_comparison);
 
+    // Check if EAX (search_value) is ASCII.
+    __ cmpl(search_value, Immediate(127));
+    __ j(kGreater, &not_found_label);
+    // Comparing byte-per-byte.
+    __ repne_scasb();
+    __ jmp(&comparison_done);
+
+    // Everything is set up for repne scasw:
+    //   * Comparison address in EDI.
+    //   * Counter in ECX.
+    __ Bind(&uncompressed_string_comparison);
+    __ repne_scasw();
+    __ Bind(&comparison_done);
+  } else {
+    __ repne_scasw();
+  }
   // Did we find a match?
   __ j(kNotEqual, &not_found_label);
 
@@ -1706,38 +1764,64 @@
   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
   DCHECK_EQ(char_size, 2u);
 
-  // Compute the address of the destination buffer.
-  __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
-  // Compute the address of the source string.
-  if (srcBegin.IsConstant()) {
-    // Compute the address of the source string by adding the number of chars from
-    // the source beginning to the value offset of a string.
-    __ leal(ESI, Address(obj, srcBegin_value * char_size + value_offset));
-  } else {
-    __ leal(ESI, Address(obj, srcBegin.AsRegister<Register>(),
-                         ScaleFactor::TIMES_2, value_offset));
-  }
-
   // Compute the number of chars (words) to move.
-  // Now is the time to save ECX, since we don't know if it will be used later.
+  // Save ECX, since we don't know if it will be used later.
   __ pushl(ECX);
   int stack_adjust = kX86WordSize;
   __ cfi().AdjustCFAOffset(stack_adjust);
   DCHECK_EQ(srcEnd, ECX);
   if (srcBegin.IsConstant()) {
-    if (srcBegin_value != 0) {
-      __ subl(ECX, Immediate(srcBegin_value));
-    }
+    __ subl(ECX, Immediate(srcBegin_value));
   } else {
     DCHECK(srcBegin.IsRegister());
     __ subl(ECX, srcBegin.AsRegister<Register>());
   }
 
-  // Do the move.
+  NearLabel done;
+  if (mirror::kUseStringCompression) {
+    // Location of count in string
+    const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    __ pushl(EAX);
+    __ cfi().AdjustCFAOffset(stack_adjust);
+
+    NearLabel copy_loop, copy_uncompressed;
+    __ cmpl(Address(obj, count_offset), Immediate(0));
+    __ j(kGreaterEqual, &copy_uncompressed);
+    // Compute the address of the source string by adding the number of chars from
+    // the source beginning to the value offset of a string.
+    __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+
+    // Start the loop to copy String's value to Array of Char.
+    __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+    __ Bind(&copy_loop);
+    __ jecxz(&done);
+    // Use EAX temporary (convert byte from ESI to word).
+    // TODO: Use LODSB/STOSW (not supported by X86Assembler) with AH initialized to 0.
+    __ movzxb(EAX, Address(ESI, 0));
+    __ movw(Address(EDI, 0), EAX);
+    __ leal(EDI, Address(EDI, char_size));
+    __ leal(ESI, Address(ESI, c_char_size));
+    // TODO: Add support for LOOP to X86Assembler.
+    __ subl(ECX, Immediate(1));
+    __ jmp(&copy_loop);
+    __ Bind(&copy_uncompressed);
+  }
+
+  // Do the copy for uncompressed string.
+  // Compute the address of the destination buffer.
+  __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+  __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
   __ rep_movsw();
 
-  // And restore ECX.
+  __ Bind(&done);
+  if (mirror::kUseStringCompression) {
+    // Restore EAX.
+    __ popl(EAX);
+    __ cfi().AdjustCFAOffset(-stack_adjust);
+  }
+  // Restore ECX.
   __ popl(ECX);
   __ cfi().AdjustCFAOffset(-stack_adjust);
 }
diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h
index 08bd197..3743cb1 100644
--- a/compiler/optimizing/intrinsics_x86.h
+++ b/compiler/optimizing/intrinsics_x86.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 0f31fab..4b0afca 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1568,14 +1568,27 @@
   __ cmpl(str, arg);
   __ j(kEqual, &return_true);
 
-  // Load length of receiver string.
+  // Load length and compression flag of receiver string.
   __ movl(rcx, Address(str, count_offset));
-  // Check if lengths are equal, return false if they're not.
+  // Check if lengths and compressiond flags are equal, return false if they're not.
+  // Two identical strings will always have same compression style since
+  // compression style is decided on alloc.
   __ cmpl(rcx, Address(arg, count_offset));
   __ j(kNotEqual, &return_false);
+
+  if (mirror::kUseStringCompression) {
+    NearLabel string_uncompressed;
+    // Both string are compressed.
+    __ cmpl(rcx, Immediate(0));
+    __ j(kGreaterEqual, &string_uncompressed);
+    // Divide string length by 2, rounding up, and continue as if uncompressed.
+    // Merge clearing the compression flag with +1 for rounding.
+    __ addl(rcx, Immediate(static_cast<int32_t>(0x80000001)));
+    __ shrl(rcx, Immediate(1));
+    __ Bind(&string_uncompressed);
+  }
   // Return true if both strings are empty.
   __ jrcxz(&return_true);
-
   // Load starting addresses of string values into RSI/RDI as required for repe_cmpsq instruction.
   __ leal(rsi, Address(str, value_offset));
   __ leal(rdi, Address(arg, value_offset));
@@ -1584,7 +1597,8 @@
   __ addl(rcx, Immediate(3));
   __ shrl(rcx, Immediate(2));
 
-  // Assertions that must hold in order to compare strings 4 characters at a time.
+  // Assertions that must hold in order to compare strings 4 characters (uncompressed)
+  // or 8 characters (compressed) at a time.
   DCHECK_ALIGNED(value_offset, 8);
   static_assert(IsAligned<8>(kObjectAlignment), "String is not zero padded");
 
@@ -1674,7 +1688,8 @@
     __ j(kAbove, slow_path->GetEntryLabel());
   }
 
-  // From here down, we know that we are looking for a char that fits in 16 bits.
+  // From here down, we know that we are looking for a char that fits in
+  // 16 bits (uncompressed) or 8 bits (compressed).
   // Location of reference to data array within the String object.
   int32_t value_offset = mirror::String::ValueOffset().Int32Value();
   // Location of count within the String object.
@@ -1682,6 +1697,12 @@
 
   // Load string length, i.e., the count field of the string.
   __ movl(string_length, Address(string_obj, count_offset));
+  if (mirror::kUseStringCompression) {
+    // Use TMP to keep string_length_flagged.
+    __ movl(CpuRegister(TMP), string_length);
+    // Mask out first bit used as compression flag.
+    __ andl(string_length, Immediate(INT32_MAX));
+  }
 
   // Do a length check.
   // TODO: Support jecxz.
@@ -1692,7 +1713,6 @@
   if (start_at_zero) {
     // Number of chars to scan is the same as the string length.
     __ movl(counter, string_length);
-
     // Move to the start of the string.
     __ addq(string_obj, Immediate(value_offset));
   } else {
@@ -1707,19 +1727,44 @@
     __ cmpl(start_index, Immediate(0));
     __ cmov(kGreater, counter, start_index, /* is64bit */ false);  // 32-bit copy is enough.
 
-    // Move to the start of the string: string_obj + value_offset + 2 * start_index.
-    __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
-
+    if (mirror::kUseStringCompression) {
+      NearLabel modify_counter, offset_uncompressed_label;
+      __ cmpl(CpuRegister(TMP), Immediate(0));
+      __ j(kGreaterEqual, &offset_uncompressed_label);
+      __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+      __ jmp(&modify_counter);
+      // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+      __ Bind(&offset_uncompressed_label);
+      __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+      __ Bind(&modify_counter);
+    } else {
+      __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+    }
     // Now update ecx, the work counter: it's gonna be string.length - start_index.
     __ negq(counter);  // Needs to be 64-bit negation, as the address computation is 64-bit.
     __ leaq(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
   }
 
-  // Everything is set up for repne scasw:
-  //   * Comparison address in RDI.
-  //   * Counter in ECX.
-  __ repne_scasw();
-
+  if (mirror::kUseStringCompression) {
+    NearLabel uncompressed_string_comparison;
+    NearLabel comparison_done;
+    __ cmpl(CpuRegister(TMP), Immediate(0));
+    __ j(kGreater, &uncompressed_string_comparison);
+    // Check if RAX (search_value) is ASCII.
+    __ cmpl(search_value, Immediate(127));
+    __ j(kGreater, &not_found_label);
+    // Comparing byte-per-byte.
+    __ repne_scasb();
+    __ jmp(&comparison_done);
+    // Everything is set up for repne scasw:
+    //   * Comparison address in RDI.
+    //   * Counter in ECX.
+    __ Bind(&uncompressed_string_comparison);
+    __ repne_scasw();
+    __ Bind(&comparison_done);
+  } else {
+    __ repne_scasw();
+  }
   // Did we find a match?
   __ j(kNotEqual, &not_found_label);
 
@@ -1871,32 +1916,54 @@
   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
   DCHECK_EQ(char_size, 2u);
 
-  // Compute the address of the destination buffer.
-  __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
-  // Compute the address of the source string.
-  if (srcBegin.IsConstant()) {
-    // Compute the address of the source string by adding the number of chars from
-    // the source beginning to the value offset of a string.
-    __ leaq(CpuRegister(RSI), Address(obj, srcBegin_value * char_size + value_offset));
-  } else {
-    __ leaq(CpuRegister(RSI), Address(obj, srcBegin.AsRegister<CpuRegister>(),
-                                      ScaleFactor::TIMES_2, value_offset));
-  }
-
+  NearLabel done;
   // Compute the number of chars (words) to move.
   __ movl(CpuRegister(RCX), srcEnd);
   if (srcBegin.IsConstant()) {
-    if (srcBegin_value != 0) {
-      __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
-    }
+    __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
   } else {
     DCHECK(srcBegin.IsRegister());
     __ subl(CpuRegister(RCX), srcBegin.AsRegister<CpuRegister>());
   }
+  if (mirror::kUseStringCompression) {
+    NearLabel copy_uncompressed, copy_loop;
+    const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+    DCHECK_EQ(c_char_size, 1u);
+    // Location of count in string.
+    const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
 
+    __ cmpl(Address(obj, count_offset), Immediate(0));
+    __ j(kGreaterEqual, &copy_uncompressed);
+    // Compute the address of the source string by adding the number of chars from
+    // the source beginning to the value offset of a string.
+    __ leaq(CpuRegister(RSI),
+            CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+    // Start the loop to copy String's value to Array of Char.
+    __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+
+    __ Bind(&copy_loop);
+    __ jrcxz(&done);
+    // Use TMP as temporary (convert byte from RSI to word).
+    // TODO: Selecting RAX as the temporary and using LODSB/STOSW.
+    __ movzxb(CpuRegister(TMP), Address(CpuRegister(RSI), 0));
+    __ movw(Address(CpuRegister(RDI), 0), CpuRegister(TMP));
+    __ leaq(CpuRegister(RDI), Address(CpuRegister(RDI), char_size));
+    __ leaq(CpuRegister(RSI), Address(CpuRegister(RSI), c_char_size));
+    // TODO: Add support for LOOP to X86_64Assembler.
+    __ subl(CpuRegister(RCX), Immediate(1));
+    __ jmp(&copy_loop);
+
+    __ Bind(&copy_uncompressed);
+  }
+
+  __ leaq(CpuRegister(RSI),
+          CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
+  // Compute the address of the destination buffer.
+  __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
   // Do the move.
   __ rep_movsw();
+
+  __ Bind(&done);
 }
 
 static void GenPeek(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h
index 155ff65..97404aa 100644
--- a/compiler/optimizing/intrinsics_x86_64.h
+++ b/compiler/optimizing/intrinsics_x86_64.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 9cfa89b..ef9bf23 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -25,7 +25,7 @@
 #include "base/stl_util.h"
 #include "intrinsics.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4dc4c20..397abde 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -32,6 +32,7 @@
 #include "handle.h"
 #include "handle_scope.h"
 #include "invoke_type.h"
+#include "intrinsics_enum.h"
 #include "locations.h"
 #include "method_reference.h"
 #include "mirror/class.h"
@@ -3690,17 +3691,6 @@
   DISALLOW_COPY_AND_ASSIGN(HNewInstance);
 };
 
-enum class Intrinsics {
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
-  k ## Name,
-#include "intrinsics_list.h"
-  kNone,
-  INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
-#undef INTRINSICS_LIST
-#undef OPTIMIZING_INTRINSICS
-};
-std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic);
-
 enum IntrinsicNeedsEnvironmentOrCache {
   kNoEnvironmentOrCache,        // Intrinsic does not require an environment or dex cache.
   kNeedsEnvironmentOrCache      // Intrinsic requires an environment or requires a dex cache.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c5d7611..d3a55dd 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -56,7 +56,6 @@
 #include "dead_code_elimination.h"
 #include "debug/elf_debug_writer.h"
 #include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
 #include "driver/compiler_driver-inl.h"
@@ -479,7 +478,7 @@
   } else if (opt_name == InstructionSimplifier::kInstructionSimplifierPassName) {
     return new (arena) InstructionSimplifier(graph, stats, pass_name.c_str());
   } else if (opt_name == IntrinsicsRecognizer::kIntrinsicsRecognizerPassName) {
-    return new (arena) IntrinsicsRecognizer(graph, driver, stats);
+    return new (arena) IntrinsicsRecognizer(graph, stats);
   } else if (opt_name == LICM::kLoopInvariantCodeMotionPassName) {
     CHECK(most_recent_side_effects != nullptr);
     return new (arena) LICM(graph, *most_recent_side_effects, stats);
@@ -743,7 +742,7 @@
       graph, stats, "instruction_simplifier$after_bce");
   InstructionSimplifier* simplify3 = new (arena) InstructionSimplifier(
       graph, stats, "instruction_simplifier$before_codegen");
-  IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, driver, stats);
+  IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, stats);
 
   HOptimization* optimizations1[] = {
     intrinsics,
@@ -899,7 +898,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(hs.NewHandle(
-        soa.Decode<mirror::ClassLoader*>(class_loader)));
+        soa.Decode<mirror::ClassLoader>(class_loader)));
     method = compiler_driver->ResolveMethod(
         soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
   }
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index dd5cb1c..2a23c92 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -22,7 +22,7 @@
 #include "common_compiler_test.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
-#include "handle_scope-inl.h"
+#include "handle_scope.h"
 #include "scoped_thread_state_change.h"
 #include "ssa_builder.h"
 #include "ssa_liveness_analysis.h"
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 4289cf7..5a47df1 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -20,7 +20,7 @@
 #include "class_linker-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index abec55f..a4a3e06 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -31,7 +31,7 @@
 #include "mirror/string.h"
 #include "nodes.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 931bbd3..05a5d0f 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -31,6 +31,7 @@
                 // SANITIZE_TARGET mode.
                 // Bug: 22233158
                 address: false,
+                coverage: false,
             },
         },
     },
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3b2715d..5d44cc1 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -49,7 +49,6 @@
 #include "compiler_callbacks.h"
 #include "debug/elf_debug_writer.h"
 #include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "dex_file-inl.h"
@@ -77,7 +76,7 @@
 #include "runtime.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "verifier/verifier_deps.h"
 #include "well_known_classes.h"
@@ -509,7 +508,6 @@
       image_patch_delta_(0),
       key_value_store_(nullptr),
       verification_results_(nullptr),
-      method_inliner_map_(),
       runtime_(nullptr),
       thread_count_(sysconf(_SC_NPROCESSORS_CONF)),
       start_ns_(NanoTime()),
@@ -1372,7 +1370,6 @@
     verification_results_.reset(new VerificationResults(compiler_options_.get()));
     callbacks_.reset(new QuickCompilerCallbacks(
         verification_results_.get(),
-        &method_inliner_map_,
         IsBootImage() ?
             CompilerCallbacks::CallbackMode::kCompileBootImage :
             CompilerCallbacks::CallbackMode::kCompileApp));
@@ -1567,7 +1564,7 @@
       ScopedObjectAccess soa(self);
       dex_caches_.push_back(soa.AddLocalReference<jobject>(
           class_linker->RegisterDexFile(*dex_file,
-                                        soa.Decode<mirror::ClassLoader*>(class_loader_))));
+                                        soa.Decode<mirror::ClassLoader>(class_loader_).Decode())));
     }
 
     return true;
@@ -1632,7 +1629,6 @@
 
     driver_.reset(new CompilerDriver(compiler_options_.get(),
                                      verification_results_.get(),
-                                     &method_inliner_map_,
                                      compiler_kind_,
                                      instruction_set_,
                                      instruction_set_features_.get(),
@@ -2540,7 +2536,6 @@
 
   std::unique_ptr<VerificationResults> verification_results_;
 
-  DexFileToMethodInlinerMap method_inliner_map_;
   std::unique_ptr<QuickCompilerCallbacks> callbacks_;
 
   std::unique_ptr<Runtime> runtime_;
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 925047f..30b708c 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -116,8 +116,7 @@
 
  public:
   CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
-      // vixl::aarch32::Disassembler::~Disassembler() will delete the stream.
-      : PrintDisassembler(new CustomDisassemblerStream(os, this, options)) {}
+      : PrintDisassembler(&disassembler_stream_), disassembler_stream_(os, this, options) {}
 
   void PrintPc(uint32_t prog_ctr) OVERRIDE {
     os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << prog_ctr << ": ";
@@ -133,6 +132,7 @@
 
  private:
   bool is_t32_;
+  CustomDisassemblerStream disassembler_stream_;
 };
 
 void DisassemblerArm::CustomDisassembler::CustomDisassemblerStream::PrintLiteral(LocationType type,
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 106cf2f..ace21aa 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -34,7 +34,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "image.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "os.h"
 
 #include "cmdline.h"
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d8ac581..be5224b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -23,6 +23,7 @@
 #include <set>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "arch/instruction_set_features.h"
@@ -42,7 +43,9 @@
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
 #include "image-inl.h"
+#include "imtable-inl.h"
 #include "indenter.h"
+#include "interpreter/unstarted_runtime.h"
 #include "linker/buffered_output_stream.h"
 #include "linker/file_output_stream.h"
 #include "mirror/array-inl.h"
@@ -55,7 +58,7 @@
 #include "oat_file_manager.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "stack_map.h"
 #include "string_reference.h"
@@ -2443,39 +2446,55 @@
   return EXIT_SUCCESS;
 }
 
-static int DumpOatWithRuntime(Runtime* runtime, OatFile* oat_file, OatDumperOptions* options,
-                              std::ostream* os) {
-  CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
-
+static jobject InstallOatFile(Runtime* runtime,
+                              std::unique_ptr<OatFile> oat_file,
+                              std::vector<const DexFile*>* class_path)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   Thread* self = Thread::Current();
   CHECK(self != nullptr);
   // Need well-known-classes.
   WellKnownClasses::Init(self->GetJniEnv());
 
   // Need to register dex files to get a working dex cache.
-  ScopedObjectAccess soa(self);
+  OatFile* oat_file_ptr = oat_file.get();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  runtime->GetOatFileManager().RegisterOatFile(std::unique_ptr<const OatFile>(oat_file));
-  std::vector<const DexFile*> class_path;
-  for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
+  runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
+  for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
     std::string error_msg;
     const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
     CHECK(dex_file != nullptr) << error_msg;
     class_linker->RegisterDexFile(*dex_file, nullptr);
-    class_path.push_back(dex_file);
+    class_path->push_back(dex_file);
   }
 
-  // Need a class loader.
-  // Fake that we're a compiler.
-  jobject class_loader = class_linker->CreatePathClassLoader(self, class_path);
+  // Need a class loader. Fake that we're a compiler.
+  // Note: this will run initializers through the unstarted runtime, so make sure it's
+  //       initialized.
+  interpreter::UnstartedRuntime::Initialize();
+
+  jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
+
+  return class_loader;
+}
+
+static int DumpOatWithRuntime(Runtime* runtime,
+                              std::unique_ptr<OatFile> oat_file,
+                              OatDumperOptions* options,
+                              std::ostream* os) {
+  CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
+  ScopedObjectAccess soa(Thread::Current());
+
+  OatFile* oat_file_ptr = oat_file.get();
+  std::vector<const DexFile*> class_path;
+  jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
 
   // Use the class loader while dumping.
-  StackHandleScope<1> scope(self);
+  StackHandleScope<1> scope(soa.Self());
   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(class_loader));
+      soa.Decode<mirror::ClassLoader>(class_loader));
   options->class_loader_ = &loader_handle;
 
-  OatDumper oat_dumper(*oat_file, *options);
+  OatDumper oat_dumper(*oat_file_ptr, *options);
   bool success = oat_dumper.Dump(*os);
   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
@@ -2494,23 +2513,23 @@
 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
                    std::ostream* os) {
   std::string error_msg;
-  OatFile* oat_file = OatFile::Open(oat_filename,
-                                    oat_filename,
-                                    nullptr,
-                                    nullptr,
-                                    false,
-                                    /*low_4gb*/false,
-                                    nullptr,
-                                    &error_msg);
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
+                                                  oat_filename,
+                                                  nullptr,
+                                                  nullptr,
+                                                  false,
+                                                  /*low_4gb*/false,
+                                                  nullptr,
+                                                  &error_msg));
   if (oat_file == nullptr) {
     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
     return EXIT_FAILURE;
   }
 
   if (runtime != nullptr) {
-    return DumpOatWithRuntime(runtime, oat_file, options, os);
+    return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
   } else {
-    return DumpOatWithoutRuntime(oat_file, options, os);
+    return DumpOatWithoutRuntime(oat_file.get(), options, os);
   }
 }
 
@@ -2547,6 +2566,444 @@
   return EXIT_SUCCESS;
 }
 
+class IMTDumper {
+ public:
+  static bool Dump(Runtime* runtime,
+                   const std::string& imt_file,
+                   bool dump_imt_stats,
+                   const char* oat_filename) {
+    Thread* self = Thread::Current();
+
+    ScopedObjectAccess soa(self);
+    StackHandleScope<1> scope(self);
+    MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
+    std::vector<const DexFile*> class_path;
+
+    if (oat_filename != nullptr) {
+      std::string error_msg;
+      std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
+                                                      oat_filename,
+                                                      nullptr,
+                                                      nullptr,
+                                                      false,
+                                                      /*low_4gb*/false,
+                                                      nullptr,
+                                                      &error_msg));
+      if (oat_file == nullptr) {
+        fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
+        return false;
+      }
+
+      class_loader.Assign(soa.Decode<mirror::ClassLoader>(
+          InstallOatFile(runtime, std::move(oat_file), &class_path)));
+    } else {
+      class_loader.Assign(nullptr);  // Boot classloader. Just here for explicit documentation.
+      class_path = runtime->GetClassLinker()->GetBootClassPath();
+    }
+
+    if (!imt_file.empty()) {
+      return DumpImt(runtime, imt_file, class_loader);
+    }
+
+    if (dump_imt_stats) {
+      return DumpImtStats(runtime, class_path, class_loader);
+    }
+
+    LOG(FATAL) << "Should not reach here";
+    UNREACHABLE();
+  }
+
+ private:
+  static bool DumpImt(Runtime* runtime,
+                      const std::string& imt_file,
+                      Handle<mirror::ClassLoader> h_class_loader)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
+    std::unordered_set<std::string> prepared;
+
+    for (const std::string& line : lines) {
+      // A line should be either a class descriptor, in which case we will dump the complete IMT,
+      // or a class descriptor and an interface method, in which case we will lookup the method,
+      // determine its IMT slot, and check the class' IMT.
+      size_t first_space = line.find(' ');
+      if (first_space == std::string::npos) {
+        DumpIMTForClass(runtime, line, h_class_loader, &prepared);
+      } else {
+        DumpIMTForMethod(runtime,
+                         line.substr(0, first_space),
+                         line.substr(first_space + 1, std::string::npos),
+                         h_class_loader,
+                         &prepared);
+      }
+      std::cerr << std::endl;
+    }
+
+    return true;
+  }
+
+  static bool DumpImtStats(Runtime* runtime,
+                           const std::vector<const DexFile*>& dex_files,
+                           Handle<mirror::ClassLoader> h_class_loader)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    size_t without_imt = 0;
+    size_t with_imt = 0;
+    std::map<size_t, size_t> histogram;
+
+    ClassLinker* class_linker = runtime->GetClassLinker();
+    const PointerSize pointer_size = class_linker->GetImagePointerSize();
+    std::unordered_set<std::string> prepared;
+
+    Thread* self = Thread::Current();
+    StackHandleScope<1> scope(self);
+    MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
+
+    for (const DexFile* dex_file : dex_files) {
+      for (uint32_t class_def_index = 0;
+           class_def_index != dex_file->NumClassDefs();
+           ++class_def_index) {
+        const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+        const char* descriptor = dex_file->GetClassDescriptor(class_def);
+        h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader));
+        if (h_klass.Get() == nullptr) {
+          std::cerr << "Warning: could not load " << descriptor << std::endl;
+          continue;
+        }
+
+        if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
+          without_imt++;
+          continue;
+        }
+
+        ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
+        if (im_table == nullptr) {
+          // Should not happen, but accept.
+          without_imt++;
+          continue;
+        }
+
+        with_imt++;
+        for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
+          ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
+          if (ptr->IsRuntimeMethod()) {
+            if (ptr->IsImtUnimplementedMethod()) {
+              histogram[0]++;
+            } else {
+              ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+              histogram[current_table->NumEntries(pointer_size)]++;
+            }
+          } else {
+            histogram[1]++;
+          }
+        }
+      }
+    }
+
+    std::cerr << "IMT stats:"
+              << std::endl << std::endl;
+
+    std::cerr << "  " << with_imt << " classes with IMT."
+              << std::endl << std::endl;
+    std::cerr << "  " << without_imt << " classes without IMT (or copy from Object)."
+              << std::endl << std::endl;
+
+    double sum_one = 0;
+    size_t count_one = 0;
+
+    std::cerr << "  " << "IMT histogram" << std::endl;
+    for (auto& bucket : histogram) {
+      std::cerr << "    " << bucket.first << " " << bucket.second << std::endl;
+      if (bucket.first > 0) {
+        sum_one += bucket.second * bucket.first;
+        count_one += bucket.second;
+      }
+    }
+
+    double count_zero = count_one + histogram[0];
+    std::cerr << "   Stats:" << std::endl;
+    std::cerr << "     Average depth (including empty): " << (sum_one / count_zero) << std::endl;
+    std::cerr << "     Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
+
+    return true;
+  }
+
+  // Return whether the given class has no IMT (or the one shared with java.lang.Object).
+  static bool HasNoIMT(Runtime* runtime,
+                       Handle<mirror::Class> klass,
+                       const PointerSize pointer_size,
+                       std::unordered_set<std::string>* prepared)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
+      return true;
+    }
+
+    if (klass->GetImt(pointer_size) == nullptr) {
+      PrepareClass(runtime, klass, prepared);
+    }
+
+    mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass();
+    DCHECK(object_class->IsObjectClass());
+
+    bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
+
+    if (klass->GetIfTable() == nullptr) {
+      DCHECK(result);
+    }
+
+    return result;
+  }
+
+  static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (table == nullptr) {
+      std::cerr << "    <No IMT?>" << std::endl;
+      return;
+    }
+    size_t table_index = 0;
+    for (;;) {
+      ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
+      if (ptr == nullptr) {
+        return;
+      }
+      table_index++;
+      std::cerr << "    " << PrettyMethod(ptr, true) << std::endl;
+    }
+  }
+
+  static ImTable* PrepareAndGetImTable(Runtime* runtime,
+                                       Thread* self,
+                                       Handle<mirror::ClassLoader> h_loader,
+                                       const std::string& class_name,
+                                       const PointerSize pointer_size,
+                                       mirror::Class** klass_out,
+                                       std::unordered_set<std::string>* prepared)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (class_name.empty()) {
+      return nullptr;
+    }
+
+    std::string descriptor;
+    if (class_name[0] == 'L') {
+      descriptor = class_name;
+    } else {
+      descriptor = DotToDescriptor(class_name.c_str());
+    }
+
+    mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader);
+
+    if (klass == nullptr) {
+      self->ClearException();
+      std::cerr << "Did not find " <<  class_name << std::endl;
+      *klass_out = nullptr;
+      return nullptr;
+    }
+
+    StackHandleScope<1> scope(Thread::Current());
+    Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
+
+    ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
+    *klass_out = h_klass.Get();
+    return ret;
+  }
+
+  static ImTable* PrepareAndGetImTable(Runtime* runtime,
+                                       Handle<mirror::Class> h_klass,
+                                       const PointerSize pointer_size,
+                                       std::unordered_set<std::string>* prepared)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    PrepareClass(runtime, h_klass, prepared);
+    return h_klass->GetImt(pointer_size);
+  }
+
+  static void DumpIMTForClass(Runtime* runtime,
+                              const std::string& class_name,
+                              Handle<mirror::ClassLoader> h_loader,
+                              std::unordered_set<std::string>* prepared)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
+    mirror::Class* klass;
+    ImTable* imt = PrepareAndGetImTable(runtime,
+                                        Thread::Current(),
+                                        h_loader,
+                                        class_name,
+                                        pointer_size,
+                                        &klass,
+                                        prepared);
+    if (imt == nullptr) {
+      return;
+    }
+
+    std::cerr << class_name << std::endl << " IMT:" << std::endl;
+    for (size_t index = 0; index < ImTable::kSize; ++index) {
+      std::cerr << "  " << index << ":" << std::endl;
+      ArtMethod* ptr = imt->Get(index, pointer_size);
+      if (ptr->IsRuntimeMethod()) {
+        if (ptr->IsImtUnimplementedMethod()) {
+          std::cerr << "    <empty>" << std::endl;
+        } else {
+          ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+          PrintTable(current_table, pointer_size);
+        }
+      } else {
+        std::cerr << "    " << PrettyMethod(ptr, true) << std::endl;
+      }
+    }
+
+    std::cerr << " Interfaces:" << std::endl;
+    // Run through iftable, find methods that slot here, see if they fit.
+    mirror::IfTable* if_table = klass->GetIfTable();
+    if (if_table != nullptr) {
+      for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
+        mirror::Class* iface = if_table->GetInterface(i);
+        std::string iface_name;
+        std::cerr << "  " << iface->GetDescriptor(&iface_name) << std::endl;
+
+        for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
+          uint32_t base_hash = ImTable::GetBaseImtHash(&iface_method);
+          uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
+          std::cerr << "    " << PrettyMethod(&iface_method, true) << " slot=" << std::dec
+              << imt_slot << " base_hash=0x" << std::hex << base_hash << std::endl;
+        }
+      }
+    }
+  }
+
+  static void DumpIMTForMethod(Runtime* runtime,
+                               const std::string& class_name,
+                               const std::string& method,
+                               Handle<mirror::ClassLoader> h_loader,
+                               std::unordered_set<std::string>* prepared)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
+    mirror::Class* klass;
+    ImTable* imt = PrepareAndGetImTable(runtime,
+                                        Thread::Current(),
+                                        h_loader,
+                                        class_name,
+                                        pointer_size,
+                                        &klass,
+                                        prepared);
+    if (imt == nullptr) {
+      return;
+    }
+
+    std::cerr << class_name << " <" << method << ">" << std::endl;
+    for (size_t index = 0; index < ImTable::kSize; ++index) {
+      ArtMethod* ptr = imt->Get(index, pointer_size);
+      if (ptr->IsRuntimeMethod()) {
+        if (ptr->IsImtUnimplementedMethod()) {
+          continue;
+        }
+
+        ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+        if (current_table == nullptr) {
+          continue;
+        }
+
+        size_t table_index = 0;
+        for (;;) {
+          ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
+          if (ptr2 == nullptr) {
+            break;
+          }
+          table_index++;
+
+          std::string p_name = PrettyMethod(ptr2, true);
+          if (StartsWith(p_name, method.c_str())) {
+            std::cerr << "  Slot "
+                      << index
+                      << " ("
+                      << current_table->NumEntries(pointer_size)
+                      << ")"
+                      << std::endl;
+            PrintTable(current_table, pointer_size);
+            return;
+          }
+        }
+      } else {
+        std::string p_name = PrettyMethod(ptr, true);
+        if (StartsWith(p_name, method.c_str())) {
+          std::cerr << "  Slot " << index << " (1)" << std::endl;
+          std::cerr << "    " << p_name << std::endl;
+        } else {
+          // Run through iftable, find methods that slot here, see if they fit.
+          mirror::IfTable* if_table = klass->GetIfTable();
+          if (if_table != nullptr) {
+            for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
+              mirror::Class* iface = if_table->GetInterface(i);
+              size_t num_methods = iface->NumDeclaredVirtualMethods();
+              if (num_methods > 0) {
+                for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
+                  if (ImTable::GetImtIndex(&iface_method) == index) {
+                    std::string i_name = PrettyMethod(&iface_method, true);
+                    if (StartsWith(i_name, method.c_str())) {
+                      std::cerr << "  Slot " << index << " (1)" << std::endl;
+                      std::cerr << "    " << p_name << " (" << i_name << ")" << std::endl;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Read lines from the given stream, dropping comments and empty lines
+  static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
+    std::vector<std::string> output;
+    while (in_stream.good()) {
+      std::string dot;
+      std::getline(in_stream, dot);
+      if (StartsWith(dot, "#") || dot.empty()) {
+        continue;
+      }
+      output.push_back(dot);
+    }
+    return output;
+  }
+
+  // Read lines from the given file, dropping comments and empty lines.
+  static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
+    std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
+    if (input_file.get() == nullptr) {
+      LOG(ERROR) << "Failed to open input file " << input_filename;
+      return std::vector<std::string>();
+    }
+    std::vector<std::string> result = ReadCommentedInputStream(*input_file);
+    input_file->close();
+    return result;
+  }
+
+  // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
+  // and note in the given set that the work was done.
+  static void PrepareClass(Runtime* runtime,
+                           Handle<mirror::Class> h_klass,
+                           std::unordered_set<std::string>* done)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (!h_klass->ShouldHaveImt()) {
+      return;
+    }
+
+    std::string name;
+    name = h_klass->GetDescriptor(&name);
+
+    if (done->find(name) != done->end()) {
+      return;
+    }
+    done->insert(name);
+
+    if (h_klass->HasSuperClass()) {
+      StackHandleScope<1> h(Thread::Current());
+      PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
+    }
+
+    if (!h_klass->IsTemp()) {
+      runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
+    }
+  }
+};
+
 struct OatdumpArgs : public CmdlineArgs {
  protected:
   using Base = CmdlineArgs;
@@ -2596,6 +3053,10 @@
       app_image_ = option.substr(strlen("--app-image=")).data();
     } else if (option.starts_with("--app-oat=")) {
       app_oat_ = option.substr(strlen("--app-oat=")).data();
+    } else if (option.starts_with("--dump-imt=")) {
+      imt_dump_ = option.substr(strlen("--dump-imt=")).data();
+    } else if (option == "--dump-imt-stats") {
+      imt_stat_dump_ = true;
     } else {
       return kParseUnknownArgument;
     }
@@ -2692,6 +3153,16 @@
         "  --addr2instr=<address>: output matching method disassembled code from relative\n"
         "                          address (e.g. PC from crash dump)\n"
         "      Example: --addr2instr=0x00001a3b\n"
+        "\n"
+        "  --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
+        "                         types and interface methods in the given file. The file\n"
+        "                         is read line-wise, where each line should either be a class\n"
+        "                         name or descriptor, or a class name/descriptor and a prefix\n"
+        "                         of a complete method name (separated by a whitespace).\n"
+        "      Example: --dump-imt=imt.txt\n"
+        "\n"
+        "  --dump-imt-stats: output IMT statistics for the given boot image\n"
+        "      Example: --dump-imt-stats"
         "\n";
 
     return usage;
@@ -2703,6 +3174,7 @@
   const char* method_filter_ = "";
   const char* image_location_ = nullptr;
   std::string elf_filename_prefix_;
+  std::string imt_dump_;
   bool dump_vmap_ = true;
   bool dump_code_info_stack_maps_ = false;
   bool disassemble_code_ = true;
@@ -2711,6 +3183,7 @@
   bool list_classes_ = false;
   bool list_methods_ = false;
   bool dump_header_only_ = false;
+  bool imt_stat_dump_ = false;
   uint32_t addr2instr_ = 0;
   const char* export_dex_location_ = nullptr;
   const char* app_image_ = nullptr;
@@ -2739,7 +3212,9 @@
         args_->app_oat_,
         args_->addr2instr_));
 
-    return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
+    return (args_->boot_image_location_ != nullptr ||
+            args_->image_location_ != nullptr ||
+            !args_->imt_dump_.empty()) &&
           !args_->symbolize_;
   }
 
@@ -2767,6 +3242,13 @@
   virtual bool ExecuteWithRuntime(Runtime* runtime) {
     CHECK(args_ != nullptr);
 
+    if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
+      return IMTDumper::Dump(runtime,
+                             args_->imt_dump_,
+                             args_->imt_stat_dump_,
+                             args_->oat_filename_);
+    }
+
     if (args_->oat_filename_ != nullptr) {
       return DumpOat(runtime,
                      args_->oat_filename_,
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 1af3660..d58f38c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -46,7 +46,7 @@
 #include "offsets.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "utils.h"
 
diff --git a/runtime/Android.bp b/runtime/Android.bp
index fd9b5b9..31f2490 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -126,6 +126,8 @@
         "mirror/executable.cc",
         "mirror/field.cc",
         "mirror/method.cc",
+        "mirror/method_handle_impl.cc",
+        "mirror/method_type.cc",
         "mirror/object.cc",
         "mirror/reference.cc",
         "mirror/stack_trace_element.cc",
@@ -546,6 +548,7 @@
         "mem_map_test.cc",
         "memory_region_test.cc",
         "mirror/dex_cache_test.cc",
+        "mirror/method_type_test.cc",
         "mirror/object_test.cc",
         "monitor_pool_test.cc",
         "monitor_test.cc",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 5d53062..cdb4c25 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1710,7 +1710,11 @@
     .cfi_rel_offset lr, 12
     ldr   r3, [r0, #MIRROR_STRING_COUNT_OFFSET]
     add   r0, #MIRROR_STRING_VALUE_OFFSET
-
+#if (STRING_COMPRESSION_FEATURE)
+    /* r4 count (with flag) and r3 holds actual length */
+    mov   r4, r3
+    bic   r3, #2147483648
+#endif
     /* Clamp start to [0..count] */
     cmp   r2, #0
     it    lt
@@ -1723,6 +1727,10 @@
     mov   r12, r0
 
     /* Build pointer to start of data to compare and pre-bias */
+#if (STRING_COMPRESSION_FEATURE)
+    cmp   r4, #0
+    blt   .Lstring_indexof_compressed
+#endif
     add   r0, r0, r2, lsl #1
     sub   r0, #2
 
@@ -1734,6 +1742,7 @@
      *   r0: start of data to test
      *   r1: char to compare
      *   r2: iteration count
+     *   r4: compression style (used temporarily)
      *   r12: original start of string data
      *   r3, r4, r10, r11 available for loading string data
      */
@@ -1791,6 +1800,22 @@
     sub   r0, r12
     asr   r0, r0, #1
     pop {r4, r10-r11, pc}
+#if (STRING_COMPRESSION_FEATURE)
+.Lstring_indexof_compressed:
+    add   r0, r0, r2
+    sub   r0, #1
+    sub   r2, r3, r2
+.Lstring_indexof_compressed_loop:
+    subs  r2, #1
+    blt   .Lindexof_nomatch
+    ldrb  r3, [r0, #1]!
+    cmp   r3, r1
+    beq   .Lstring_indexof_compressed_matched
+    b     .Lstring_indexof_compressed_loop
+.Lstring_indexof_compressed_matched:
+    sub   r0, r12
+    pop {r4, r10-r11, pc}
+#endif
 END art_quick_indexof
 
     /* Assembly routines used to handle ABI differences. */
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index eee949d..04a3cc6 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2378,7 +2378,11 @@
 ENTRY art_quick_indexof
     ldr   w3, [x0, #MIRROR_STRING_COUNT_OFFSET]
     add   x0, x0, #MIRROR_STRING_VALUE_OFFSET
-
+#if (STRING_COMPRESSION_FEATURE)
+    /* w4 holds count (with flag) and w3 holds actual length */
+    mov   w4, w3
+    and   w3, w3, #2147483647
+#endif
     /* Clamp start to [0..count] */
     cmp   w2, #0
     csel  w2, wzr, w2, lt
@@ -2388,10 +2392,12 @@
     /* Save a copy to compute result */
     mov   x5, x0
 
+#if (STRING_COMPRESSION_FEATURE)
+    tbnz  w4, #31, .Lstring_indexof_compressed
+#endif
     /* Build pointer to start of data to compare and pre-bias */
     add   x0, x0, x2, lsl #1
     sub   x0, x0, #2
-
     /* Compute iteration count */
     sub   w2, w3, w2
 
@@ -2456,6 +2462,26 @@
     sub   x0, x0, x5
     asr   x0, x0, #1
     ret
+#if (STRING_COMPRESSION_FEATURE)
+   /*
+    * Comparing compressed string character-per-character with
+    * input character
+    */
+.Lstring_indexof_compressed:
+    add   x0, x0, x2
+    sub   x0, x0, #1
+    sub   w2, w3, w2
+.Lstring_indexof_compressed_loop:
+    subs  w2, w2, #1
+    b.lt  .Lindexof_nomatch
+    ldrb  w6, [x0, #1]!
+    cmp   w6, w1
+    b.eq  .Lstring_indexof_compressed_matched
+    b     .Lstring_indexof_compressed_loop
+.Lstring_indexof_compressed_matched:
+    sub   x0, x0, x5
+    ret
+#endif
 END art_quick_indexof
 
     /*
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index 7bbc709..0b8e531 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -19,7 +19,7 @@
 #include <gtest/gtest.h>
 
 #ifdef ART_TARGET_ANDROID
-#include "cutils/properties.h"
+#include "android-base/properties.h"
 #endif
 
 #include "base/logging.h"
@@ -40,8 +40,8 @@
 
   // Read the variant property.
   std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
-  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
-  if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+  std::string dex2oat_isa_variant = android::base::GetProperty(key, "");
+  if (!dex2oat_isa_variant.empty()) {
     // Use features from property to build InstructionSetFeatures and check against build's
     // features.
     std::string error_msg;
@@ -68,13 +68,13 @@
   // Read the variant property.
   std::string variant_key = StringPrintf("dalvik.vm.isa.%s.variant",
                                          GetInstructionSetString(kRuntimeISA));
-  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
-  if (property_get(variant_key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+  std::string dex2oat_isa_variant = android::base::GetProperty(variant_key, "");
+  if (!dex2oat_isa_variant.empty()) {
     // Read the features property.
     std::string features_key = StringPrintf("dalvik.vm.isa.%s.features",
                                             GetInstructionSetString(kRuntimeISA));
-    char dex2oat_isa_features[PROPERTY_VALUE_MAX];
-    if (property_get(features_key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+    std::string dex2oat_isa_features = android::base::GetProperty(features_key, "");
+    if (!dex2oat_isa_features.empty()) {
       // Use features from property to build InstructionSetFeatures and check against build's
       // features.
       std::string error_msg;
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 3424e3c..5e39f42 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -26,7 +26,7 @@
 #include "linear_alloc.h"
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -1796,7 +1796,7 @@
 
   ScopedObjectAccess soa(self);
   StackHandleScope<3> hs(self);
-  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(o)));
+  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(o)));
   Handle<mirror::Class> c(hs.NewHandle(obj->GetClass()));
   // Need a method as a referrer
   ArtMethod* m = c->GetDirectMethod(0, kRuntimePointerSize);
@@ -1995,11 +1995,11 @@
 
   jobject jarray_list = env->NewObject(arraylist_jclass, arraylist_constructor);
   ASSERT_NE(nullptr, jarray_list);
-  Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object*>(jarray_list)));
+  Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object>(jarray_list)));
 
   jobject jobj = env->NewObject(obj_jclass, obj_constructor);
   ASSERT_NE(nullptr, jobj);
-  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(jobj)));
+  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(jobj)));
 
   // Invocation tests.
 
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 879d496..7bb59ef 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1986,11 +1986,70 @@
     mov MIRROR_STRING_COUNT_OFFSET(%ecx), %ebx
     lea MIRROR_STRING_VALUE_OFFSET(%eax), %esi
     lea MIRROR_STRING_VALUE_OFFSET(%ecx), %edi
+#if (STRING_COMPRESSION_FEATURE)
+    /* Differ cases */
+    cmpl    LITERAL(0), %edx
+    jl      .Lstring_compareto_this_is_compressed
+    cmpl    LITERAL(0), %ebx
+    jl      .Lstring_compareto_that_is_compressed
+    jmp     .Lstring_compareto_both_not_compressed
+.Lstring_compareto_this_is_compressed:
+    andl    LITERAL(0x7FFFFFFF), %edx
+    cmpl    LITERAL(0), %ebx
+    jl      .Lstring_compareto_both_compressed
+    /* If (this->IsCompressed() && that->IsCompressed() == false) */
+    mov     %edx, %eax
+    subl    %ebx, %eax
+    mov     %edx, %ecx
+    cmovg   %ebx, %ecx
+    /* Going into loop to compare each character */
+    jecxz   .Lstring_compareto_keep_length            // check loop counter (if 0, don't compare)
+.Lstring_compareto_loop_comparison_this_compressed:
+    movzbl  (%esi), %edx                              // move *(this_cur_char) byte to long
+    movzwl  (%edi), %ebx                              // move *(that_cur_char) word to long
+    addl    LITERAL(1), %esi                          // ++this_cur_char (8-bit)
+    addl    LITERAL(2), %edi                          // ++that_cur_char (16-bit)
+    subl    %ebx, %edx
+    loope   .Lstring_compareto_loop_comparison_this_compressed
+    cmovne  %edx, %eax                        // return eax = *(this_cur_char) - *(that_cur_char)
+    jmp     .Lstring_compareto_return
+.Lstring_compareto_that_is_compressed:
+    andl    LITERAL(0x7FFFFFFF), %ebx
+    mov     %edx, %eax
+    subl    %ebx, %eax
+    mov     %edx, %ecx
+    cmovg   %ebx, %ecx
+    /* If (this->IsCompressed() == false && that->IsCompressed()) */
+    jecxz   .Lstring_compareto_keep_length            // check loop counter, if 0, don't compare
+.Lstring_compareto_loop_comparison_that_compressed:
+    movzwl  (%esi), %edx                              // move *(this_cur_char) word to long
+    movzbl  (%edi), %ebx                              // move *(that_cur_char) byte to long
+    addl    LITERAL(2), %esi                          // ++this_cur_char (16-bit)
+    addl    LITERAL(1), %edi                          // ++that_cur_char (8-bit)
+    subl    %ebx, %edx
+    loope   .Lstring_compareto_loop_comparison_that_compressed
+    cmovne  %edx, %eax
+    jmp     .Lstring_compareto_return         // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_both_compressed:
+    andl    LITERAL(0x7FFFFFFF), %ebx
     /* Calculate min length and count diff */
-    mov   %edx, %ecx
-    mov   %edx, %eax
-    subl  %ebx, %eax
-    cmovg %ebx, %ecx
+    mov     %edx, %ecx
+    mov     %edx, %eax
+    subl    %ebx, %eax
+    cmovg   %ebx, %ecx
+    jecxz   .Lstring_compareto_keep_length
+    repe    cmpsb
+    je      .Lstring_compareto_keep_length
+    movzbl  -1(%esi), %eax        // get last compared char from this string (8-bit)
+    movzbl  -1(%edi), %ecx        // get last compared char from comp string (8-bit)
+    jmp     .Lstring_compareto_count_difference
+#endif // STRING_COMPRESSION_FEATURE
+.Lstring_compareto_both_not_compressed:
+    /* Calculate min length and count diff */
+    mov     %edx, %ecx
+    mov     %edx, %eax
+    subl    %ebx, %eax
+    cmovg   %ebx, %ecx
     /*
      * At this point we have:
      *   eax: value to return if first part of strings are equal
@@ -1998,18 +2057,15 @@
      *   esi: pointer to this string data
      *   edi: pointer to comp string data
      */
-    jecxz .Lkeep_length
-    repe cmpsw                    // find nonmatching chars in [%esi] and [%edi], up to length %ecx
-    jne .Lnot_equal
-.Lkeep_length:
-    POP edi                       // pop callee save reg
-    POP esi                       // pop callee save reg
-    ret
-    .balign 16
-.Lnot_equal:
-    movzwl  -2(%esi), %eax        // get last compared char from this string
-    movzwl  -2(%edi), %ecx        // get last compared char from comp string
-    subl  %ecx, %eax              // return the difference
+    jecxz .Lstring_compareto_keep_length
+    repe  cmpsw                   // find nonmatching chars in [%esi] and [%edi], up to length %ecx
+    je    .Lstring_compareto_keep_length
+    movzwl  -2(%esi), %eax        // get last compared char from this string (16-bit)
+    movzwl  -2(%edi), %ecx        // get last compared char from comp string (16-bit)
+.Lstring_compareto_count_difference:
+    subl    %ecx, %eax
+.Lstring_compareto_keep_length:
+.Lstring_compareto_return:
     POP edi                       // pop callee save reg
     POP esi                       // pop callee save reg
     ret
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index a11e402..54e52e5 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2100,11 +2100,70 @@
     /* Build pointers to the start of string data */
     leal MIRROR_STRING_VALUE_OFFSET(%edi), %edi
     leal MIRROR_STRING_VALUE_OFFSET(%esi), %esi
+#if (STRING_COMPRESSION_FEATURE)
+    /* Differ cases */
+    cmpl LITERAL(0), %r8d
+    jl      .Lstring_compareto_this_is_compressed
+    cmpl    LITERAL(0), %r9d
+    jl      .Lstring_compareto_that_is_compressed
+    jmp     .Lstring_compareto_both_not_compressed
+.Lstring_compareto_this_is_compressed:
+    andl    LITERAL(0x7FFFFFFF), %r8d
+    cmpl    LITERAL(0), %r9d
+    jl      .Lstring_compareto_both_compressed
+    /* Comparison this (8-bit) and that (16-bit) */
+    mov     %r8d, %eax
+    subl    %r9d, %eax
+    mov     %r8d, %ecx
+    cmovg   %r9d, %ecx
+    /* Going into loop to compare each character */
+    jecxz   .Lstring_compareto_keep_length      // check loop counter (if 0 then stop)
+.Lstring_compareto_loop_comparison_this_compressed:
+    movzbl  (%edi), %r8d                        // move *(this_cur_char) byte to long
+    movzwl  (%esi), %r9d                        // move *(that_cur_char) word to long
+    addl    LITERAL(1), %edi                    // ++this_cur_char (8-bit)
+    addl    LITERAL(2), %esi                    // ++that_cur_char (16-bit)
+    subl    %r9d, %r8d
+    loope   .Lstring_compareto_loop_comparison_this_compressed
+    cmovne  %r8d, %eax                          // return eax = *(this_cur_char) - *(that_cur_char)
+    ret
+.Lstring_compareto_that_is_compressed:
+    andl    LITERAL(0x7FFFFFFF), %r9d
+    movl    %r8d, %eax
+    subl    %r9d, %eax
+    mov     %r8d, %ecx
+    cmovg   %r9d, %ecx
+    /* Comparison this (8-bit) and that (16-bit) */
+    jecxz   .Lstring_compareto_keep_length      // check loop counter (if 0, don't compare)
+.Lstring_compareto_loop_comparison_that_compressed:
+    movzwl  (%edi), %r8d                        // move *(this_cur_char) word to long
+    movzbl  (%esi), %r9d                        // move *(that_cur_chat) byte to long
+    addl    LITERAL(2), %edi                    // ++this_cur_char (16-bit)
+    addl    LITERAL(1), %esi                    // ++that_cur_char (8-bit)
+    subl    %r9d, %r8d
+    loope   .Lstring_compareto_loop_comparison_that_compressed
+    cmovne  %r8d, %eax                          // return eax = *(this_cur_char) - *(that_cur_char)
+    ret
+.Lstring_compareto_both_compressed:
+    andl    LITERAL(0x7FFFFFFF), %r9d
     /* Calculate min length and count diff */
-    movl  %r8d, %ecx
-    movl  %r8d, %eax
-    subl  %r9d, %eax
-    cmovg %r9d, %ecx
+    movl    %r8d, %ecx
+    movl    %r8d, %eax
+    subl    %r9d, %eax
+    cmovg   %r9d, %ecx
+    jecxz   .Lstring_compareto_keep_length
+    repe    cmpsb
+    je      .Lstring_compareto_keep_length
+    movzbl  -1(%edi), %eax        // get last compared char from this string (8-bit)
+    movzbl  -1(%esi), %ecx        // get last compared char from comp string (8-bit)
+    jmp     .Lstring_compareto_count_difference
+#endif // STRING_COMPRESSION_FEATURE
+.Lstring_compareto_both_not_compressed:
+    /* Calculate min length and count diff */
+    movl    %r8d, %ecx
+    movl    %r8d, %eax
+    subl    %r9d, %eax
+    cmovg   %r9d, %ecx
     /*
      * At this point we have:
      *   eax: value to return if first part of strings are equal
@@ -2112,16 +2171,14 @@
      *   esi: pointer to comp string data
      *   edi: pointer to this string data
      */
-    jecxz .Lkeep_length
-    repe cmpsw                    // find nonmatching chars in [%esi] and [%edi], up to length %ecx
-    jne .Lnot_equal
-.Lkeep_length:
-    ret
-    .balign 16
-.Lnot_equal:
-    movzwl  -2(%edi), %eax        // get last compared char from this string
-    movzwl  -2(%esi), %ecx        // get last compared char from comp string
+    jecxz .Lstring_compareto_keep_length
+    repe  cmpsw                   // find nonmatching chars in [%esi] and [%edi], up to length %ecx
+    je    .Lstring_compareto_keep_length
+    movzwl  -2(%edi), %eax        // get last compared char from this string (16-bit)
+    movzwl  -2(%esi), %ecx        // get last compared char from comp string (16-bit)
+.Lstring_compareto_count_difference:
     subl  %ecx, %eax              // return the difference
+.Lstring_compareto_keep_length:
     ret
 END_FUNCTION art_quick_string_compareto
 
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ef75f94..ca96169 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -28,7 +28,7 @@
 #include "mirror/object-inl.h"
 #include "primitive.h"
 #include "thread-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index ea5078e..3b4db0b 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -24,7 +24,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "well_known_classes.h"
 
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 73cce5e..73c6cf1 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -36,7 +36,7 @@
 #include "quick/quick_method_frame_info.h"
 #include "read_barrier-inl.h"
 #include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 193bea1..c97c328 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -40,7 +40,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -52,7 +52,7 @@
 
 ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject jlr_method) {
-  auto* executable = soa.Decode<mirror::Executable*>(jlr_method);
+  ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(jlr_method);
   DCHECK(executable != nullptr);
   return executable->GetArtMethod();
 }
@@ -350,7 +350,7 @@
   ScopedObjectAccess soa(self);
   StackHandleScope<1> shs(self);
 
-  mirror::Class* annotation = soa.Decode<mirror::Class*>(klass);
+  ObjPtr<mirror::Class> annotation = soa.Decode<mirror::Class>(klass);
   DCHECK(annotation->IsAnnotation());
   Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
 
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 3d2db69..7a8f479 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -137,7 +137,52 @@
     return (GetAccessFlags() & kAccFinal) != 0;
   }
 
+  bool IsIntrinsic() {
+    return (GetAccessFlags() & kAccIntrinsic) != 0;
+  }
+
+  void SetIntrinsic(uint32_t intrinsic) {
+    DCHECK(IsUint<8>(intrinsic));
+    uint32_t new_value = (GetAccessFlags() & kAccFlagsNotUsedByIntrinsic) |
+        kAccIntrinsic |
+        (intrinsic << POPCOUNT(kAccFlagsNotUsedByIntrinsic));
+    if (kIsDebugBuild) {
+      uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
+      bool is_constructor = IsConstructor();
+      bool is_synchronized = IsSynchronized();
+      bool skip_access_checks = SkipAccessChecks();
+      bool is_fast_native = IsFastNative();
+      bool is_copied = IsCopied();
+      bool is_miranda = IsMiranda();
+      bool is_default = IsDefault();
+      bool is_default_conflict = IsDefaultConflicting();
+      bool is_compilable = IsCompilable();
+      bool must_count_locks = MustCountLocks();
+      SetAccessFlags(new_value);
+      DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
+      DCHECK_EQ(is_constructor, IsConstructor());
+      DCHECK_EQ(is_synchronized, IsSynchronized());
+      DCHECK_EQ(skip_access_checks, SkipAccessChecks());
+      DCHECK_EQ(is_fast_native, IsFastNative());
+      DCHECK_EQ(is_copied, IsCopied());
+      DCHECK_EQ(is_miranda, IsMiranda());
+      DCHECK_EQ(is_default, IsDefault());
+      DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
+      DCHECK_EQ(is_compilable, IsCompilable());
+      DCHECK_EQ(must_count_locks, MustCountLocks());
+    } else {
+      SetAccessFlags(new_value);
+    }
+  }
+
+  uint32_t GetIntrinsic() {
+    DCHECK(IsIntrinsic());
+    return (GetAccessFlags() >> POPCOUNT(kAccFlagsNotUsedByIntrinsic)) & kAccMaxIntrinsic;
+  }
+
   bool IsCopied() {
+    static_assert((kAccCopied & kAccFlagsNotUsedByIntrinsic) == kAccCopied,
+                  "kAccCopied conflicts with intrinsic modifier");
     const bool copied = (GetAccessFlags() & kAccCopied) != 0;
     // (IsMiranda() || IsDefaultConflicting()) implies copied
     DCHECK(!(IsMiranda() || IsDefaultConflicting()) || copied)
@@ -146,6 +191,8 @@
   }
 
   bool IsMiranda() {
+    static_assert((kAccMiranda & kAccFlagsNotUsedByIntrinsic) == kAccMiranda,
+                  "kAccMiranda conflicts with intrinsic modifier");
     return (GetAccessFlags() & kAccMiranda) != 0;
   }
 
@@ -156,6 +203,9 @@
   }
 
   bool IsCompilable() {
+    if (IsIntrinsic()) {
+      return true;
+    }
     return (GetAccessFlags() & kAccCompileDontBother) == 0;
   }
 
@@ -163,11 +213,16 @@
   // multiple default methods. It cannot be invoked, throwing an IncompatibleClassChangeError if one
   // attempts to do so.
   bool IsDefaultConflicting() {
+    if (IsIntrinsic()) {
+      return false;
+    }
     return (GetAccessFlags() & kAccDefaultConflict) != 0u;
   }
 
   // This is set by the class linker.
   bool IsDefault() {
+    static_assert((kAccDefault & kAccFlagsNotUsedByIntrinsic) == kAccDefault,
+                  "kAccDefault conflicts with intrinsic modifier");
     return (GetAccessFlags() & kAccDefault) != 0;
   }
 
@@ -204,6 +259,9 @@
   // Should this method be run in the interpreter and count locks (e.g., failed structured-
   // locking verification)?
   bool MustCountLocks() {
+    if (IsIntrinsic()) {
+      return false;
+    }
     return (GetAccessFlags() & kAccMustCountLocks) != 0;
   }
 
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index b8f7272..567791e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -240,7 +240,9 @@
 #define MIRROR_STRING_VALUE_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_STRING_VALUE_OFFSET, art::mirror::String::ValueOffset().Int32Value())
 
-
+// String compression feature.
+#define STRING_COMPRESSION_FEATURE 0
+ADD_TEST_EQ(STRING_COMPRESSION_FEATURE, art::mirror::kUseStringCompression);
 
 #if defined(__cplusplus)
 }  // End of CheckAsmSupportOffsets.
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 9d56954..1183dea 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -26,7 +26,7 @@
 #include "base/value_object.h"
 #include "mutex-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 8af9fa5..91e31d8 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -78,7 +78,6 @@
   kAllocSpaceLock,
   kBumpPointerSpaceBlockLock,
   kArenaPoolLock,
-  kDexFileMethodInlinerLock,
   kDexFileToMethodInlinerMapLock,
   kInternTableLock,
   kOatFileSecondaryLookupLock,
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index a980535..9f07702 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -36,7 +36,7 @@
 #include "mirror/string-inl.h"
 #include "mirror/throwable.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "well_known_classes.h"
 
@@ -269,12 +269,12 @@
    */
   bool CheckInstanceFieldID(ScopedObjectAccess& soa, jobject java_object, jfieldID fid)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     if (o == nullptr) {
       AbortF("field operation on NULL object: %p", java_object);
       return false;
     }
-    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
+    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o.Decode())) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("field operation on invalid %s: %p",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
@@ -333,15 +333,15 @@
       return false;
     }
     if (invoke != kVirtual) {
-      mirror::Class* c = soa.Decode<mirror::Class*>(jc);
-      if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+      ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
+      if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
         AbortF("can't call %s %s with class %s", invoke == kStatic ? "static" : "nonvirtual",
             PrettyMethod(m).c_str(), PrettyClass(c).c_str());
         return false;
       }
     }
     if (invoke != kStatic) {
-      mirror::Object* o = soa.Decode<mirror::Object*>(jobj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(jobj);
       if (o == nullptr) {
         AbortF("can't call %s on null object", PrettyMethod(m).c_str());
         return false;
@@ -360,12 +360,12 @@
    */
   bool CheckStaticFieldID(ScopedObjectAccess& soa, jclass java_class, jfieldID fid)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     ArtField* f = CheckFieldID(soa, fid);
     if (f == nullptr) {
       return false;
     }
-    if (f->GetDeclaringClass() != c) {
+    if (c != f->GetDeclaringClass()) {
       AbortF("static jfieldID %p not valid for class %s", fid, PrettyClass(c).c_str());
       return false;
     }
@@ -387,8 +387,8 @@
     if (m == nullptr) {
       return false;
     }
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
-    if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
+    if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
       AbortF("can't call static %s on class %s", PrettyMethod(m).c_str(), PrettyClass(c).c_str());
       return false;
     }
@@ -408,7 +408,7 @@
     if (m == nullptr) {
       return false;
     }
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     if (o == nullptr) {
       AbortF("can't call %s on null object", PrettyMethod(m).c_str());
       return false;
@@ -557,14 +557,14 @@
 
   bool CheckReflectedMethod(ScopedObjectAccess& soa, jobject jmethod)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* method = soa.Decode<mirror::Object*>(jmethod);
+    ObjPtr<mirror::Object> method = soa.Decode<mirror::Object>(jmethod);
     if (method == nullptr) {
       AbortF("expected non-null method");
       return false;
     }
     mirror::Class* c = method->GetClass();
-    if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method) != c &&
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) != c &&
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
       AbortF("expected java.lang.reflect.Method or "
           "java.lang.reflect.Constructor but got object of type %s: %p",
           PrettyTypeOf(method).c_str(), jmethod);
@@ -589,13 +589,13 @@
 
   bool CheckReflectedField(ScopedObjectAccess& soa, jobject jfield)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* field = soa.Decode<mirror::Object*>(jfield);
+    ObjPtr<mirror::Object> field = soa.Decode<mirror::Object>(jfield);
     if (field == nullptr) {
       AbortF("expected non-null java.lang.reflect.Field");
       return false;
     }
     mirror::Class* c = field->GetClass();
-    if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Field) != c) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Field) != c) {
       AbortF("expected java.lang.reflect.Field but got object of type %s: %p",
              PrettyTypeOf(field).c_str(), jfield);
       return false;
@@ -605,10 +605,10 @@
 
   bool CheckThrowable(ScopedObjectAccess& soa, jthrowable jobj)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
     if (!obj->GetClass()->IsThrowableClass()) {
       AbortF("expected java.lang.Throwable but got object of type "
-             "%s: %p", PrettyTypeOf(obj).c_str(), obj);
+             "%s: %p", PrettyTypeOf(obj).c_str(), obj.Decode());
       return false;
     }
     return true;
@@ -616,10 +616,10 @@
 
   bool CheckThrowableClass(ScopedObjectAccess& soa, jclass jc)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
     if (!c->IsThrowableClass()) {
       AbortF("expected java.lang.Throwable class but got object of "
-             "type %s: %p", PrettyDescriptor(c).c_str(), c);
+             "type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
       return false;
     }
     return true;
@@ -647,9 +647,9 @@
 
   bool CheckInstantiableNonArray(ScopedObjectAccess& soa, jclass jc)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
     if (!c->IsInstantiableNonArray()) {
-      AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c);
+      AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
       return false;
     }
     return true;
@@ -660,7 +660,7 @@
     if (!CheckArray(soa, array)) {
       return false;
     }
-    mirror::Array* a = soa.Decode<mirror::Array*>(array);
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(array);
     if (a->GetClass()->GetComponentType()->GetPrimitiveType() != type) {
       AbortF("incompatible array type %s expected %s[]: %p",
              PrettyDescriptor(a->GetClass()).c_str(), PrettyDescriptor(type).c_str(), array);
@@ -692,20 +692,20 @@
       return false;
     }
     if (is_static) {
-      mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
       if (o == nullptr || !o->IsClass()) {
         AbortF("attempt to access static field %s with a class argument of type %s: %p",
                PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
         return false;
       }
-      mirror::Class* c = o->AsClass();
-      if (field->GetDeclaringClass() != c) {
+      ObjPtr<mirror::Class> c = o->AsClass();
+      if (c != field->GetDeclaringClass()) {
         AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
                PrettyField(field).c_str(), PrettyDescriptor(c).c_str(), fid);
         return false;
       }
     } else {
-      mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
       if (o == nullptr || !field->GetDeclaringClass()->IsAssignableFrom(o->GetClass())) {
         AbortF("attempt to access field %s from an object argument of type %s: %p",
                PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
@@ -763,7 +763,7 @@
       }
     }
 
-    mirror::Object* obj = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_object);
     if (obj == nullptr) {
       // Either java_object is invalid or is a cleared weak.
       IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -772,12 +772,12 @@
         okay = false;
       } else {
         obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref);
-        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj);
+        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj.Decode());
       }
       if (!okay) {
         AbortF("%s is an invalid %s: %p (%p)",
                what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
-               java_object, obj);
+               java_object, obj.Decode());
         return false;
       }
     }
@@ -786,7 +786,7 @@
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("%s is an invalid %s: %p (%p)",
              what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
-             java_object, obj);
+             java_object, obj.Decode());
       return false;
     }
 
@@ -936,10 +936,10 @@
         break;
       case 'c': {  // jclass
         jclass jc = arg.c;
-        mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+        ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
         if (c == nullptr) {
           *msg += "NULL";
-        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
+        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c.Decode())) {
           StringAppendF(msg, "INVALID POINTER:%p", jc);
         } else if (!c->IsClass()) {
           *msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
@@ -1107,12 +1107,12 @@
       return false;
     }
 
-    mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
-    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a))) {
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
+    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a.Decode()))) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("jarray is an invalid %s: %p (%p)",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_array)).c_str(),
-             java_array, a);
+             java_array, a.Decode());
       return false;
     } else if (!a->IsArrayInstance()) {
       AbortF("jarray argument has non-array type: %s", PrettyTypeOf(a).c_str());
@@ -1411,7 +1411,7 @@
                                    void* original_ptr) {
     ScopedObjectAccess soa(env);
 
-    mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
     size_t component_size = a->GetClass()->GetComponentSize();
     size_t byte_count = a->GetLength() * component_size;
     void* result = Create(original_ptr, byte_count, true);
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 843d4c1..ab712f9 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -19,7 +19,7 @@
 
 #include "art_method-inl.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
 
 namespace art {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index caabcde..51e5aae 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -67,9 +67,10 @@
   // MethodVerifier refuses methods with string_idx out of bounds.
   DCHECK_LT(string_idx, declaring_class->GetDexFile().NumStringIds());;
   mirror::String* string =
-        mirror::StringDexCachePair::LookupString(declaring_class->GetDexCacheStrings(),
-                                                 string_idx,
-                                                 mirror::DexCache::kDexCacheStringCacheSize).Read();
+        mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+                                           string_idx,
+                                           mirror::DexCache::kDexCacheStringCacheSize).Read();
+  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(string == nullptr)) {
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
@@ -84,6 +85,7 @@
 
 inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
   mirror::Class* resolved_type = referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
+  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(resolved_type == nullptr)) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
     StackHandleScope<2> hs(Thread::Current());
@@ -101,6 +103,7 @@
   mirror::Class* declaring_class = referrer->GetDeclaringClass();
   mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache();
   mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx);
+  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(resolved_type == nullptr)) {
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr));
@@ -148,6 +151,7 @@
                                              ArtMethod* referrer,
                                              InvokeType type) {
   ArtMethod* resolved_method = GetResolvedMethod(method_idx, referrer);
+  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(resolved_method == nullptr)) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
     StackHandleScope<2> hs(self);
@@ -179,6 +183,7 @@
                                            bool is_static) {
   mirror::Class* declaring_class = referrer->GetDeclaringClass();
   ArtField* resolved_field = GetResolvedField(field_idx, declaring_class);
+  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(resolved_field == nullptr)) {
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c51b99a..0a1f7a9 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -73,6 +73,8 @@
 #include "mirror/field.h"
 #include "mirror/iftable-inl.h"
 #include "mirror/method.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/proxy.h"
@@ -89,7 +91,7 @@
 #include "os.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "trace.h"
 #include "utils.h"
@@ -636,6 +638,18 @@
   SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
   mirror::Method::SetArrayClass(class_root);
 
+  // Create java.lang.invoke.MethodType.class root
+  class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;");
+  CHECK(class_root != nullptr);
+  SetClassRoot(kJavaLangInvokeMethodType, class_root);
+  mirror::MethodType::SetClass(class_root);
+
+  // Create java.lang.invoke.MethodHandleImpl.class root
+  class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;");
+  CHECK(class_root != nullptr);
+  SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root);
+  mirror::MethodHandleImpl::SetClass(class_root);
+
   // java.lang.ref classes need to be specially flagged, but otherwise are normal classes
   // finish initializing Reference class
   mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
@@ -1032,6 +1046,8 @@
   mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
   mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
   mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
+  mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
+  mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl));
   mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
   mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
   mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
@@ -1069,8 +1085,8 @@
 bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                     mirror::ClassLoader* class_loader) {
   return class_loader == nullptr ||
-      class_loader->GetClass() ==
-          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader);
+       soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader) ==
+           class_loader->GetClass();
 }
 
 static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa,
@@ -1109,8 +1125,8 @@
   CHECK(dex_path_list_field != nullptr);
   CHECK(dex_elements_field != nullptr);
   while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
-    if (class_loader->GetClass() !=
-        soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+        class_loader->GetClass()) {
       *error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str());
       // Unsupported class loader.
       return false;
@@ -1292,8 +1308,8 @@
           mirror::StringDexCacheType* const strings =
               reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset());
           for (size_t j = 0; j < num_strings; ++j) {
-            DCHECK_EQ(strings[j].load(std::memory_order_relaxed).string_index, 0u);
-            DCHECK(strings[j].load(std::memory_order_relaxed).string_pointer.IsNull());
+            DCHECK_EQ(strings[j].load(std::memory_order_relaxed).index, 0u);
+            DCHECK(strings[j].load(std::memory_order_relaxed).object.IsNull());
             strings[j].store(image_resolved_strings[j].load(std::memory_order_relaxed),
                              std::memory_order_relaxed);
           }
@@ -1687,7 +1703,7 @@
         return false;
       }
       // Add the temporary dex path list elements at the end.
-      auto* elements = soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements);
+      auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
       for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
         mirror::Object* element = elements->GetWithoutChecks(i);
         if (element != nullptr) {
@@ -2032,6 +2048,8 @@
   mirror::IntArray::ResetArrayClass();
   mirror::LongArray::ResetArrayClass();
   mirror::ShortArray::ResetArrayClass();
+  mirror::MethodType::ResetClass();
+  mirror::MethodHandleImpl::ResetClass();
   Thread* const self = Thread::Current();
   for (const ClassLoaderData& data : class_loaders_) {
     DeleteClassLoader(self, data);
@@ -2109,8 +2127,8 @@
   if (kIsDebugBuild) {
     // Sanity check to make sure all the dex cache arrays are empty. b/28992179
     for (size_t i = 0; i < num_strings; ++i) {
-      CHECK_EQ(strings[i].load(std::memory_order_relaxed).string_index, 0u);
-      CHECK(strings[i].load(std::memory_order_relaxed).string_pointer.IsNull());
+      CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u);
+      CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull());
     }
     for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) {
       CHECK(types[i].Read<kWithoutReadBarrier>() == nullptr);
@@ -2169,6 +2187,7 @@
                                            const char* descriptor,
                                            mirror::Class* klass) {
   DCHECK(klass != nullptr);
+  Thread::PoisonObjectPointersIfDebug();
 
   // For temporary classes we must wait for them to be retired.
   if (init_done_ && klass->IsTemp()) {
@@ -2285,8 +2304,8 @@
   }
 
   // Unsupported class-loader?
-  if (class_loader->GetClass() !=
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+  if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+      class_loader->GetClass()) {
     *result = nullptr;
     return false;
   }
@@ -2380,7 +2399,7 @@
   DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
   DCHECK(self != nullptr);
   self->AssertNoPendingException();
-  self->PoisonObjectPointers();
+  self->PoisonObjectPointers();  // For DefineClass, CreateArrayClass, etc...
   if (descriptor[1] == '\0') {
     // only the descriptors of primitive types should be 1 character long, also avoid class lookup
     // for primitive classes that aren't backed by dex files.
@@ -2463,7 +2482,7 @@
       return nullptr;
     } else {
       // success, return mirror::Class*
-      return soa.Decode<mirror::Class*>(result.get());
+      return soa.Decode<mirror::Class>(result.get()).Decode();
     }
   }
   UNREACHABLE();
@@ -4186,9 +4205,9 @@
   // Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
   // the methods.
   klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
-  klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
+  klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader).Decode());
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
-  klass->SetName(soa.Decode<mirror::String*>(name));
+  klass->SetName(soa.Decode<mirror::String>(name).Decode());
   klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
   mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
   std::string descriptor(GetDescriptorForProxy(klass.Get()));
@@ -4226,7 +4245,7 @@
   const size_t num_direct_methods = 1;
 
   // They have as many virtual methods as the array
-  auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods));
+  auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
   DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
       << PrettyClass(h_methods->GetClass());
   const size_t num_virtual_methods = h_methods->GetLength();
@@ -4268,7 +4287,7 @@
     // Link the fields and virtual methods, creating vtable and iftables.
     // The new class will replace the old one in the class table.
     Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
-        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
     if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) {
       mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
       return nullptr;
@@ -4279,11 +4298,13 @@
   klass.Assign(new_class.Get());
 
   CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
-  interfaces_sfield.SetObject<false>(klass.Get(),
-                                     soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+  interfaces_sfield.SetObject<false>(
+      klass.Get(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
   CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
   throws_sfield.SetObject<false>(
-      klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+      klass.Get(),
+      soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
 
   {
     // Lock on klass is released. Lock new class object.
@@ -4303,7 +4324,7 @@
     }
 
     StackHandleScope<1> hs2(self);
-    Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String*>(name));
+    Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name));
     std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
                                                    decoded_name->ToModifiedUtf8().c_str()));
     CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name);
@@ -4313,9 +4334,9 @@
     CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
 
     CHECK_EQ(klass.Get()->GetInterfaces(),
-             soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+             soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
     CHECK_EQ(klass.Get()->GetThrows(),
-             soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
+             soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
   }
   return klass.Get();
 }
@@ -7526,6 +7547,7 @@
                                            Handle<mirror::DexCache> dex_cache) {
   DCHECK(dex_cache.Get() != nullptr);
   mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved != nullptr) {
     return resolved;
   }
@@ -7568,6 +7590,7 @@
                                         Handle<mirror::ClassLoader> class_loader) {
   DCHECK(dex_cache.Get() != nullptr);
   mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved == nullptr) {
     Thread* self = Thread::Current();
     const char* descriptor = dex_file.StringByTypeIdx(type_idx);
@@ -7606,6 +7629,7 @@
   DCHECK(dex_cache.Get() != nullptr);
   // Check for hit in the dex cache.
   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
     if (kResolveMode == ClassLinker::kForceICCECheck) {
@@ -7809,6 +7833,7 @@
                                                        Handle<mirror::DexCache> dex_cache,
                                                        Handle<mirror::ClassLoader> class_loader) {
   ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
     return resolved;
@@ -7841,6 +7866,7 @@
                                     bool is_static) {
   DCHECK(dex_cache.Get() != nullptr);
   ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved != nullptr) {
     return resolved;
   }
@@ -7883,6 +7909,7 @@
                                        Handle<mirror::ClassLoader> class_loader) {
   DCHECK(dex_cache.Get() != nullptr);
   ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+  Thread::PoisonObjectPointersIfDebug();
   if (resolved != nullptr) {
     return resolved;
   }
@@ -8064,6 +8091,8 @@
     "[Ljava/lang/reflect/Constructor;",
     "[Ljava/lang/reflect/Field;",
     "[Ljava/lang/reflect/Method;",
+    "Ljava/lang/invoke/MethodHandleImpl;",
+    "Ljava/lang/invoke/MethodType;",
     "Ljava/lang/ClassLoader;",
     "Ljava/lang/Throwable;",
     "Ljava/lang/ClassNotFoundException;",
@@ -8166,7 +8195,7 @@
 
   // Create PathClassLoader.
   Handle<mirror::Class> h_path_class_class = hs.NewHandle(
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+      soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader));
   Handle<mirror::Object> h_path_class_loader = hs.NewHandle(
       h_path_class_class->AllocObject(self));
   DCHECK(h_path_class_loader.Get() != nullptr);
@@ -8183,7 +8212,7 @@
                                "Ljava/lang/ClassLoader;");
   DCHECK(parent_field != nullptr);
   mirror::Object* boot_cl =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
   parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
 
   // Make it a global ref and return.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 954af76..8f7051e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -51,6 +51,7 @@
   class DexCachePointerArray;
   class DexCacheTest_Open_Test;
   class IfTable;
+  class MethodType;
   template<class T> class ObjectArray;
   class StackTraceElement;
 }  // namespace mirror
@@ -99,6 +100,8 @@
     kJavaLangReflectConstructorArrayClass,
     kJavaLangReflectFieldArrayClass,
     kJavaLangReflectMethodArrayClass,
+    kJavaLangInvokeMethodHandleImpl,
+    kJavaLangInvokeMethodType,
     kJavaLangClassLoader,
     kJavaLangThrowable,
     kJavaLangClassNotFoundException,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7023081..a5aa0d0 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -33,6 +33,8 @@
 #include "mirror/dex_cache.h"
 #include "mirror/executable.h"
 #include "mirror/field.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/proxy.h"
@@ -40,7 +42,7 @@
 #include "mirror/stack_trace_element.h"
 #include "mirror/string-inl.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -708,6 +710,27 @@
   };
 };
 
+struct MethodTypeOffsets : public CheckOffsets<mirror::MethodType> {
+  MethodTypeOffsets() : CheckOffsets<mirror::MethodType>(
+      false, "Ljava/lang/invoke/MethodType;") {
+    addOffset(OFFSETOF_MEMBER(mirror::MethodType, form_), "form");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodType, method_descriptor_), "methodDescriptor");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodType, p_types_), "ptypes");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodType, r_type_), "rtype");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodType, wrap_alt_), "wrapAlt");
+  }
+};
+
+struct MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
+  MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
+      false, "Ljava/lang/invoke/MethodHandle;") {
+    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, art_field_or_method_), "artFieldOrMethod");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, as_type_cache_), "asTypeCache");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, handle_kind_), "handleKind");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, method_type_), "type");
+  }
+};
+
 // C++ fields must exactly match the fields in the Java classes. If this fails,
 // reorder the fields in the C++ class. Managed class fields are ordered by
 // ClassLinker::LinkFields.
@@ -726,6 +749,8 @@
   EXPECT_TRUE(AccessibleObjectOffsets().Check());
   EXPECT_TRUE(FieldOffsets().Check());
   EXPECT_TRUE(ExecutableOffsets().Check());
+  EXPECT_TRUE(MethodTypeOffsets().Check());
+  EXPECT_TRUE(MethodHandleImplOffsets().Check());
 }
 
 TEST_F(ClassLinkerTest, FindClassNonexistent) {
@@ -752,7 +777,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Nested"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Nested"))));
 
   mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
   ASSERT_TRUE(outer != nullptr);
@@ -786,7 +811,7 @@
 
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   AssertNonExistentClass("LMyClass;");
   mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
   ASSERT_TRUE(MyClass != nullptr);
@@ -912,9 +937,9 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader_1(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   Handle<mirror::ClassLoader> class_loader_2(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   mirror::Class* MyClass_1 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1);
   mirror::Class* MyClass_2 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2);
   EXPECT_TRUE(MyClass_1 != nullptr);
@@ -926,7 +951,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
   Handle<mirror::Class> statics(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
   class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
@@ -1003,7 +1028,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<6> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Interfaces"))));
   Handle<mirror::Class> I(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
   Handle<mirror::Class> J(
@@ -1072,7 +1097,7 @@
   const DexFile* dex_file = GetFirstDexFile(jclass_loader);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
   ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
   ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
@@ -1202,7 +1227,7 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
   Handle<mirror::Class> statics(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
 
@@ -1217,7 +1242,7 @@
 
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
 
   // java.lang.Object is a bootstrap class.
   Handle<mirror::Class> jlo_class(
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 11722b2..eda1ddd 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -47,7 +47,7 @@
 #include "os.h"
 #include "primitive.h"
 #include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "well_known_classes.h"
 
@@ -511,12 +511,12 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader));
+      soa.Decode<mirror::ClassLoader>(jclass_loader));
 
   DCHECK_EQ(class_loader->GetClass(),
-            soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+            soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader).Decode());
   DCHECK_EQ(class_loader->GetParent()->GetClass(),
-            soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader));
+            soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader).Decode());
 
   // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
   // We need to get the DexPathList and loop through it.
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6ed44fc..0206cae 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -48,7 +48,7 @@
 #include "mirror/throwable.h"
 #include "reflection.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "handle_scope-inl.h"
@@ -390,7 +390,8 @@
     return nullptr;
   }
 
-  mirror::Class* java_lang_Thread = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+  ObjPtr<mirror::Class> java_lang_Thread =
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
   if (!java_lang_Thread->IsAssignableFrom(thread_peer->GetClass())) {
     // This isn't a thread.
     *error = JDWP::ERR_INVALID_THREAD;
@@ -431,21 +432,22 @@
     return JDWP::JT_CLASS_OBJECT;
   }
   {
-    mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+    ObjPtr<mirror::Class> thread_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
     if (thread_class->IsAssignableFrom(c)) {
       return JDWP::JT_THREAD;
     }
   }
   {
-    mirror::Class* thread_group_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+    ObjPtr<mirror::Class> thread_group_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
     if (thread_group_class->IsAssignableFrom(c)) {
       return JDWP::JT_THREAD_GROUP;
     }
   }
   {
-    mirror::Class* class_loader_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
+    ObjPtr<mirror::Class> class_loader_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader);
     if (class_loader_class->IsAssignableFrom(c)) {
       return JDWP::JT_CLASS_LOADER;
     }
@@ -1946,7 +1948,8 @@
   }
   {
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    mirror::Class* java_lang_String = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_String);
+    ObjPtr<mirror::Class> java_lang_String =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_String);
     if (!java_lang_String->IsAssignableFrom(obj->GetClass())) {
       // This isn't a string.
       return JDWP::ERR_INVALID_STRING;
@@ -2014,7 +2017,7 @@
     expandBufAddObjectId(pReply, JDWP::ObjectId(0));
     error = JDWP::ERR_NONE;
   } else if (error == JDWP::ERR_NONE) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
     CHECK(c != nullptr);
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
     CHECK(f != nullptr);
@@ -2038,7 +2041,8 @@
     *error = JDWP::ERR_INVALID_OBJECT;
     return nullptr;
   }
-  mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+  ObjPtr<mirror::Class> c =
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
   CHECK(c != nullptr);
   if (!c->IsAssignableFrom(thread_group->GetClass())) {
     // This is not a java.lang.ThreadGroup.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index e0d5337..5763479 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -255,7 +255,7 @@
   }
 
   mirror::Class* annotation_member_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
+      soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember).Decode();
   mirror::Class* annotation_member_array_class =
       class_linker->FindArrayClass(self, &annotation_member_class);
   if (annotation_member_array_class == nullptr) {
@@ -572,7 +572,7 @@
   *annotation_ptr = annotation;
 
   if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) {
-    element_object = BoxPrimitive(primitive_type, annotation_value->value_);
+    element_object = BoxPrimitive(primitive_type, annotation_value->value_).Decode();
     set_object = true;
   }
 
@@ -782,7 +782,7 @@
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<2> hs(self);
   Handle<mirror::Class> annotation_array_class(hs.NewHandle(
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array)));
   if (annotation_set == nullptr) {
     return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
   }
@@ -840,7 +840,7 @@
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<1> hs(self);
   mirror::Class* annotation_array_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
   mirror::Class* annotation_array_array_class =
       Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
   if (annotation_array_array_class == nullptr) {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8dd5f37..8e1501f 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -24,7 +24,7 @@
 #include "dex_file-inl.h"
 #include "mem_map.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index c5a4d75..e392870 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -27,7 +27,7 @@
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
 #include "leb128.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 2681ad0..9f28c8c 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -19,7 +19,7 @@
 #include "base/stl_util.h"
 #include "common_runtime_test.h"
 #include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index fd9ffbd..38ee468 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -33,7 +33,7 @@
 #include "nth_caller_visitor.h"
 #include "oat_quick_method_header.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -160,12 +160,12 @@
       } else {
         JValue jv;
         jv.SetJ(args.at(i).j);
-        mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+        mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv).Decode();
         if (val == nullptr) {
           CHECK(soa.Self()->IsExceptionPending());
           return zero;
         }
-        soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(args_jobj)->Set<false>(i, val);
       }
     }
   }
@@ -187,13 +187,13 @@
       return zero;
     } else {
       ArtMethod* interface_method =
-          soa.Decode<mirror::Method*>(interface_method_jobj)->GetArtMethod();
+          soa.Decode<mirror::Method>(interface_method_jobj)->GetArtMethod();
       // This can cause thread suspension.
       PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
       mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */, pointer_size);
-      mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
+      ObjPtr<mirror::Object> result_ref = soa.Decode<mirror::Object>(result);
       JValue result_unboxed;
-      if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
+      if (!UnboxPrimitiveForResult(result_ref.Decode(), result_type, &result_unboxed)) {
         DCHECK(soa.Self()->IsExceptionPending());
         return zero;
       }
@@ -207,9 +207,9 @@
       bool declares_exception = false;
       {
         ScopedAssertNoThreadSuspension ants(__FUNCTION__);
-        mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+        ObjPtr<mirror::Object> rcvr = soa.Decode<mirror::Object>(rcvr_jobj);
         mirror::Class* proxy_class = rcvr->GetClass();
-        mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
+        ObjPtr<mirror::Method> interface_method = soa.Decode<mirror::Method>(interface_method_jobj);
         ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
             interface_method->GetArtMethod(), kRuntimePointerSize);
         auto virtual_methods = proxy_class->GetVirtualMethodsSlice(kRuntimePointerSize);
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 22226c1..fd23ced 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -18,7 +18,7 @@
 #include "base/logging.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index cfd948e..c52bc8e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -36,7 +36,7 @@
 #include "oat_quick_method_header.h"
 #include "quick_exception_handler.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "debugger.h"
 
@@ -834,7 +834,7 @@
 void BuildQuickArgumentVisitor::FixupReferences() {
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
-    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
     soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
@@ -926,7 +926,7 @@
 void RememberForGcArgumentVisitor::FixupReferences() {
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
-    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
     soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc
index 819cb85..67ab14c 100644
--- a/runtime/gc/accounting/card_table_test.cc
+++ b/runtime/gc/accounting/card_table_test.cc
@@ -23,7 +23,7 @@
 #include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"  // Strings are easiest to allocate
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_pool.h"
 #include "utils.h"
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index ab8942a..8b91075 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -32,7 +32,7 @@
 #include "intern_table.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 #include "well_known_classes.h"
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index ad3dd33..b89d99c 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -41,7 +41,7 @@
 #include "mark_sweep-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index b0ca18e..6d61c64 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -50,6 +50,7 @@
     CHECK_EQ(self->GetState(), kRunnable);
     self->AssertThreadSuspensionIsAllowable();
     self->AssertNoPendingException();
+    self->PoisonObjectPointers();
   }
   // Need to check that we arent the large object allocator since the large object allocation code
   // path this function. If we didn't check we would have an infinite loop.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4e6dd2b..88e4624 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -61,6 +61,7 @@
 #include "intern_table.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
+#include "obj_ptr-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
@@ -69,7 +70,7 @@
 #include "reflection.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "thread_list.h"
 #include "well_known_classes.h"
@@ -1507,13 +1508,14 @@
       << static_cast<int>(100 * managed_utilization) << "%.";
 }
 
-bool Heap::IsValidObjectAddress(const mirror::Object* obj) const {
+bool Heap::IsValidObjectAddress(ObjPtr<mirror::Object> obj) const {
   // Note: we deliberately don't take the lock here, and mustn't test anything that would require
   // taking the lock.
   if (obj == nullptr) {
     return true;
   }
-  return IsAligned<kObjectAlignment>(obj) && FindSpaceFromObject(obj, true) != nullptr;
+  return IsAligned<kObjectAlignment>(obj.Decode()) &&
+      FindSpaceFromObject(obj.Decode(), true) != nullptr;
 }
 
 bool Heap::IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const {
@@ -3565,9 +3567,9 @@
   max_allowed_footprint_ = max_allowed_footprint;
 }
 
-bool Heap::IsMovableObject(const mirror::Object* obj) const {
+bool Heap::IsMovableObject(ObjPtr<mirror::Object> obj) const {
   if (kMovingCollector) {
-    space::Space* space = FindContinuousSpaceFromObject(obj, true);
+    space::Space* space = FindContinuousSpaceFromObject(obj.Decode(), true);
     if (space != nullptr) {
       // TODO: Check large object?
       return space->CanMoveObjects();
@@ -3727,7 +3729,7 @@
   args[0].l = arg.get();
   InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
   // Restore object in case it gets moved.
-  *object = soa.Decode<mirror::Object*>(arg.get());
+  *object = soa.Decode<mirror::Object>(arg.get()).Decode();
 }
 
 void Heap::RequestConcurrentGCAndSaveObject(Thread* self, bool force_full, mirror::Object** obj) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 10bebef..e32f057 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -34,6 +34,7 @@
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
+#include "obj_ptr.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "process_state.h"
@@ -274,7 +275,7 @@
   // A weaker test than IsLiveObject or VerifyObject that doesn't require the heap lock,
   // and doesn't abort on error, allowing the caller to report more
   // meaningful diagnostics.
-  bool IsValidObjectAddress(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsValidObjectAddress(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Faster alternative to IsHeapAddress since finding if an object is in the large object space is
   // very slow.
@@ -290,7 +291,7 @@
       REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
   // Returns true if there is any chance that the object (obj) will move.
-  bool IsMovableObject(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsMovableObject(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Enables us to compacting GC until objects are released.
   void IncrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_);
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index a3cefd9..515a6fd 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -22,7 +22,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index e172f85..9694597 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -24,7 +24,7 @@
 #include "reference_processor-inl.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "task_processor.h"
 #include "utils.h"
 #include "well_known_classes.h"
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
index 2a1635d..5b8a3c2 100644
--- a/runtime/gc/reference_queue_test.cc
+++ b/runtime/gc/reference_queue_test.cc
@@ -20,7 +20,7 @@
 #include "reference_queue.h"
 #include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 16d1f93..0030326 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -27,7 +27,7 @@
 #include "base/stl_util.h"
 #include "image.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "space-inl.h"
 #include "thread-inl.h"
 
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index 170f927..7bc4dc4 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -18,7 +18,7 @@
 
 #include "dlmalloc_space.h"
 #include "rosalloc_space.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index bd600fe..17d7c87 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -26,7 +26,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "zygote_space.h"
 
diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc
index 7c1ec8a..af8a444 100644
--- a/runtime/gc/system_weak_test.cc
+++ b/runtime/gc/system_weak_test.cc
@@ -26,7 +26,7 @@
 #include "handle_scope-inl.h"
 #include "heap.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
index a49121b..0704a68 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -17,7 +17,7 @@
 #include "task_processor.h"
 
 #include "base/time_utils.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/handle.h b/runtime/handle.h
index d4c13d4..c41010a 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -23,6 +23,7 @@
 #include "base/mutex.h"
 #include "base/value_object.h"
 #include "jni.h"
+#include "obj_ptr.h"
 #include "stack_reference.h"
 
 namespace art {
@@ -130,6 +131,14 @@
     return old;
   }
 
+  ALWAYS_INLINE T* Assign(ObjPtr<T> reference) REQUIRES_SHARED(Locks::mutator_lock_) {
+    StackReference<mirror::Object>* ref = Handle<T>::GetReference();
+    T* old = down_cast<T*>(ref->AsMirrorPtr());
+    ref->Assign(reference.Decode());
+    return old;
+  }
+
+
   template<typename S>
   explicit MutableHandle(const MutableHandle<S>& handle) REQUIRES_SHARED(Locks::mutator_lock_)
       : Handle<T>(handle) {
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 2e1b8ed3..75a0391 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -21,6 +21,7 @@
 
 #include "base/mutex.h"
 #include "handle.h"
+#include "obj_ptr-inl.h"
 #include "thread-inl.h"
 #include "verify_object-inl.h"
 
@@ -107,12 +108,21 @@
   return h;
 }
 
+template<size_t kNumReferences> template<class MirrorType, bool kPoison>
+inline MutableHandle<MirrorType> StackHandleScope<kNumReferences>::NewHandle(
+    ObjPtr<MirrorType, kPoison> object) {
+  return NewHandle(object.Decode());
+}
+
 template<size_t kNumReferences> template<class T>
 inline HandleWrapper<T> StackHandleScope<kNumReferences>::NewHandleWrapper(T** object) {
-  SetReference(pos_, *object);
-  MutableHandle<T> h(GetHandle<T>(pos_));
-  pos_++;
-  return HandleWrapper<T>(object, h);
+  return HandleWrapper<T>(object, NewHandle(*object));
+}
+
+template<size_t kNumReferences> template<class T>
+inline HandleWrapperObjPtr<T> StackHandleScope<kNumReferences>::NewHandleWrapper(
+    ObjPtr<T>* object) {
+  return HandleWrapperObjPtr<T>(object, NewHandle(*object));
 }
 
 template<size_t kNumReferences>
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 37eed99..2b283ae 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -28,6 +28,9 @@
 #include "verify_object.h"
 
 namespace art {
+
+template<class MirrorType, bool kPoison> class ObjPtr;
+
 namespace mirror {
 class Object;
 }
@@ -125,7 +128,7 @@
 };
 
 // A wrapper which wraps around Object** and restores the pointer in the destructor.
-// TODO: Add more functionality.
+// TODO: Delete
 template<class T>
 class HandleWrapper : public MutableHandle<T> {
  public:
@@ -143,6 +146,26 @@
   T** const obj_;
 };
 
+
+// A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
+// TODO: Add more functionality.
+template<class T>
+class HandleWrapperObjPtr : public MutableHandle<T> {
+ public:
+  HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
+      : MutableHandle<T>(handle), obj_(obj) {}
+
+  HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
+
+  ~HandleWrapperObjPtr() {
+    *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
+  }
+
+ private:
+  ObjPtr<T>* const obj_;
+};
+
+
 // Scoped handle storage of a fixed size that is usually stack allocated.
 template<size_t kNumReferences>
 class PACKED(4) StackHandleScope FINAL : public HandleScope {
@@ -157,6 +180,14 @@
   ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template<class T>
+  ALWAYS_INLINE HandleWrapperObjPtr<T> NewHandleWrapper(ObjPtr<T>* object)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<class MirrorType, bool kPoison>
+  ALWAYS_INLINE MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType, kPoison> object)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index 58f3800..c269a37 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -17,7 +17,7 @@
 #include "base/enums.h"
 #include "gtest/gtest.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 921dde1..ecb2157 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -59,7 +59,7 @@
 #include "mirror/object-inl.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/image.cc b/runtime/image.cc
index 7e6790a..299d5fd 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -25,7 +25,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '0', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '1', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 1f39a1e..202e472 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -21,7 +21,7 @@
 #include "nth_caller_visitor.h"
 #include "reference_table.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "utils.h"
 #include "verify_object-inl.h"
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 61bcadd..58d487d 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -19,7 +19,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index abe3184..7f9f04f 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -25,7 +25,7 @@
 #include "handle_scope-inl.h"
 #include "jvalue.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "thread-inl.h"
 
@@ -458,7 +458,7 @@
   instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
   ClassLinker* class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
   ASSERT_TRUE(klass != nullptr);
   ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
@@ -505,7 +505,7 @@
   instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
   ClassLinker* class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
   ASSERT_TRUE(klass != nullptr);
   ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 620e15b..74cec57 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -20,7 +20,7 @@
 #include "mirror/object.h"
 #include "handle_scope-inl.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 0003e72..c270df7 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -23,7 +23,7 @@
 #include "interpreter_mterp_impl.h"
 #include "interpreter_switch_impl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "stack.h"
 #include "unstarted_runtime.h"
@@ -51,7 +51,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), klass.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jclass);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -93,7 +93,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), klass.get(), arg0.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "IIZ") {
       typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -191,7 +191,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), rcvr.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jobject);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -212,7 +212,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), rcvr.get(), arg0.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
       ScopedThreadStateChange tsc(self, kNative);
     } else if (shorty == "III") {
       typedef jint (fntype)(JNIEnv*, jobject, jint, jint);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 814adf7..0feb013 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -254,9 +254,9 @@
   DCHECK_LT(string_idx % mirror::DexCache::kDexCacheStringCacheSize,
             declaring_class->GetDexFile().NumStringIds());
   mirror::String* string_ptr =
-      mirror::StringDexCachePair::LookupString(declaring_class->GetDexCacheStrings(),
-                                               string_idx,
-                                               mirror::DexCache::kDexCacheStringCacheSize).Read();
+      mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+                                         string_idx,
+                                         mirror::DexCache::kDexCacheStringCacheSize).Read();
   if (UNLIKELY(string_ptr == nullptr)) {
     StackHandleScope<1> hs(self);
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 98e358b..39846da 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1619,9 +1619,9 @@
     uint32_t* args ATTRIBUTE_UNUSED, JValue* result) {
   ScopedObjectAccessUnchecked soa(self);
   if (Runtime::Current()->IsActiveTransaction()) {
-    result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<true>(soa)));
+    result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<true>(soa)).Decode());
   } else {
-    result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<false>(soa)));
+    result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<false>(soa)).Decode());
   }
 }
 
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index ba751ec..6a4add3 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -31,7 +31,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/string-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "transaction.h"
 
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 979495a..0c752ef 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -36,7 +36,7 @@
 #include "runtime-inl.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
@@ -532,17 +532,17 @@
   return true;
 }
 
-jobject JavaVMExt::AddGlobalRef(Thread* self, mirror::Object* obj) {
+jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
   // Check for null after decoding the object to handle cleared weak globals.
   if (obj == nullptr) {
     return nullptr;
   }
   WriterMutexLock mu(self, globals_lock_);
-  IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj);
+  IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
   return reinterpret_cast<jobject>(ref);
 }
 
-jweak JavaVMExt::AddWeakGlobalRef(Thread* self, mirror::Object* obj) {
+jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
   if (obj == nullptr) {
     return nullptr;
   }
@@ -550,7 +550,7 @@
   while (UNLIKELY(!MayAccessWeakGlobals(self))) {
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
-  IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj);
+  IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
   return reinterpret_cast<jweak>(ref);
 }
 
@@ -755,15 +755,15 @@
     ScopedObjectAccess soa(env);
     // As the incoming class loader is reachable/alive during the call of this function,
     // it's okay to decode it without worrying about unexpectedly marking it alive.
-    mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(class_loader);
+    ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
 
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (class_linker->IsBootClassLoader(soa, loader)) {
+    if (class_linker->IsBootClassLoader(soa, loader.Decode())) {
       loader = nullptr;
       class_loader = nullptr;
     }
 
-    class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader);
+    class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Decode());
     CHECK(class_loader_allocator != nullptr);
   }
   if (library != nullptr) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index a10a72f..558ffff 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -22,6 +22,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "indirect_reference_table.h"
+#include "obj_ptr.h"
 #include "reference_table.h"
 
 namespace art {
@@ -123,10 +124,10 @@
   void BroadcastForNewWeakGlobals() REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!weak_globals_lock_);
 
-  jobject AddGlobalRef(Thread* self, mirror::Object* obj)
+  jobject AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!globals_lock_);
 
-  jweak AddWeakGlobalRef(Thread* self, mirror::Object* obj)
+  jweak AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
     REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_);
 
   void DeleteGlobalRef(Thread* self, jobject obj) REQUIRES(!globals_lock_);
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index e2d29fe..6aebe9f9 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -30,7 +30,7 @@
 #include "jdwp/jdwp_expand_buf.h"
 #include "jdwp/jdwp_priv.h"
 #include "jdwp/object_registry.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 #include "handle_scope-inl.h"
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index f6008ac..0f2d188 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -31,7 +31,7 @@
 #include "jdwp/jdwp_expand_buf.h"
 #include "jdwp/jdwp_priv.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index dbf04fe..e3bf3e5 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -25,7 +25,7 @@
 #include "base/time_utils.h"
 #include "debugger.h"
 #include "jdwp/jdwp_priv.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 5989b61..9ba62c9 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -19,7 +19,7 @@
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index c9227b1..2c6b249 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -32,7 +32,7 @@
 #include "linear_alloc.h"
 #include "mem_map.h"
 #include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index c8f4d94..764458a 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -26,7 +26,7 @@
 #include "mirror/class_loader.h"
 #include "handle_scope-inl.h"
 #include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index a4bc3fc..d23821b 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -26,7 +26,7 @@
 #include "base/time_utils.h"
 #include "compiler_filter.h"
 #include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 
 namespace art {
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 216df2f..6ba187e 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -20,7 +20,7 @@
 #include "dex_instruction.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index a11f9ab..7b27578 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -52,7 +52,7 @@
 #include "reflection.h"
 #include "runtime.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "thread.h"
 #include "utf.h"
@@ -108,7 +108,7 @@
                                  "%s is null at index %d", kind, idx);
 }
 
-static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
+static ObjPtr<mirror::Class> EnsureInitialized(Thread* self, ObjPtr<mirror::Class> klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (LIKELY(klass->IsInitialized())) {
     return klass;
@@ -124,7 +124,7 @@
 static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
                               const char* name, const char* sig, bool is_static)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class));
+  ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class));
   if (c == nullptr) {
     return nullptr;
   }
@@ -143,31 +143,31 @@
     }
   }
   if (method == nullptr || method->IsStatic() != is_static) {
-    ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
+    ThrowNoSuchMethodError(soa, c.Decode(), name, sig, is_static ? "static" : "non-static");
     return nullptr;
   }
   return soa.EncodeMethod(method);
 }
 
-static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
+static ObjPtr<mirror::ClassLoader> GetClassLoader(const ScopedObjectAccess& soa)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ArtMethod* method = soa.Self()->GetCurrentMethod(nullptr);
   // If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
   if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
-    return soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+    return soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
   }
   // If we have a method, use its ClassLoader for context.
   if (method != nullptr) {
     return method->GetDeclaringClass()->GetClassLoader();
   }
   // We don't have a method, so try to use the system ClassLoader.
-  mirror::ClassLoader* class_loader =
-      soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+  ObjPtr<mirror::ClassLoader> class_loader =
+      soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader());
   if (class_loader != nullptr) {
     return class_loader;
   }
   // See if the override ClassLoader is set for gtests.
-  class_loader = soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+  class_loader = soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
   if (class_loader != nullptr) {
     // If so, CommonCompilerTest should have marked the runtime as a compiler not compiling an
     // image.
@@ -184,7 +184,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::Class> c(
-      hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class))));
+      hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class))));
   if (c.Get() == nullptr) {
     return nullptr;
   }
@@ -272,7 +272,7 @@
   if (mid == nullptr) {
     ScopedObjectAccess soa(env);
     LOG(ERROR) << "No <init>" << signature << " in "
-        << PrettyClass(soa.Decode<mirror::Class*>(exception_class));
+        << PrettyClass(soa.Decode<mirror::Class>(exception_class));
     return JNI_ERR;
   }
 
@@ -282,7 +282,7 @@
     return JNI_ERR;
   }
   ScopedObjectAccess soa(env);
-  soa.Self()->SetException(soa.Decode<mirror::Throwable*>(exception.get()));
+  soa.Self()->SetException(soa.Decode<mirror::Throwable>(exception.get()).Decode());
   return JNI_OK;
 }
 
@@ -363,12 +363,12 @@
   static jfieldID FromReflectedField(JNIEnv* env, jobject jlr_field) {
     CHECK_NON_NULL_ARGUMENT(jlr_field);
     ScopedObjectAccess soa(env);
-    mirror::Object* obj_field = soa.Decode<mirror::Object*>(jlr_field);
+    ObjPtr<mirror::Object> obj_field = soa.Decode<mirror::Object>(jlr_field);
     if (obj_field->GetClass() != mirror::Field::StaticClass()) {
       // Not even a java.lang.reflect.Field, return null. TODO, is this check necessary?
       return nullptr;
     }
-    auto* field = static_cast<mirror::Field*>(obj_field);
+    ObjPtr<mirror::Field> field = down_cast<mirror::Field*>(obj_field.Decode());
     return soa.EncodeField(field->GetArtField());
   }
 
@@ -398,14 +398,14 @@
   static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
     CHECK_NON_NULL_ARGUMENT(java_object);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     return soa.AddLocalReference<jclass>(o->GetClass());
   }
 
   static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     return soa.AddLocalReference<jclass>(c->IsInterface() ? nullptr : c->GetSuperClass());
   }
 
@@ -415,9 +415,9 @@
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class1, JNI_FALSE);
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class2, JNI_FALSE);
     ScopedObjectAccess soa(env);
-    mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
-    mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
-    return c2->IsAssignableFrom(c1) ? JNI_TRUE : JNI_FALSE;
+    ObjPtr<mirror::Class> c1 = soa.Decode<mirror::Class>(java_class1);
+    ObjPtr<mirror::Class> c2 = soa.Decode<mirror::Class>(java_class2);
+    return c2->IsAssignableFrom(c1.Decode()) ? JNI_TRUE : JNI_FALSE;
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
@@ -427,19 +427,19 @@
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
-      mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+      ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
+      ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
       return obj->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
     }
   }
 
   static jint Throw(JNIEnv* env, jthrowable java_exception) {
     ScopedObjectAccess soa(env);
-    mirror::Throwable* exception = soa.Decode<mirror::Throwable*>(java_exception);
+    ObjPtr<mirror::Throwable> exception = soa.Decode<mirror::Throwable>(java_exception);
     if (exception == nullptr) {
       return JNI_ERR;
     }
-    soa.Self()->SetException(exception);
+    soa.Self()->SetException(exception.Decode());
     return JNI_OK;
   }
 
@@ -509,7 +509,7 @@
 
   static jobject PopLocalFrame(JNIEnv* env, jobject java_survivor) {
     ScopedObjectAccess soa(env);
-    mirror::Object* survivor = soa.Decode<mirror::Object*>(java_survivor);
+    ObjPtr<mirror::Object> survivor = soa.Decode<mirror::Object>(java_survivor);
     soa.Env()->PopFrame();
     return soa.AddLocalReference<jobject>(survivor);
   }
@@ -522,8 +522,8 @@
 
   static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
-    return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+    return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj.Decode());
   }
 
   static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
@@ -534,8 +534,8 @@
 
   static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
-    return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+    return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj.Decode());
   }
 
   static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
@@ -546,7 +546,7 @@
 
   static jobject NewLocalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
     // Check for null after decoding the object to handle cleared weak globals.
     if (decoded_obj == nullptr) {
       return nullptr;
@@ -579,7 +579,7 @@
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      return (soa.Decode<mirror::Object*>(obj1) == soa.Decode<mirror::Object*>(obj2))
+      return (soa.Decode<mirror::Object>(obj1) == soa.Decode<mirror::Object>(obj2))
               ? JNI_TRUE : JNI_FALSE;
     }
   }
@@ -587,7 +587,7 @@
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -613,7 +613,8 @@
     CHECK_NON_NULL_ARGUMENT(java_class);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+                                                soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -639,7 +640,8 @@
     CHECK_NON_NULL_ARGUMENT(java_class);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+                                                soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -1223,9 +1225,9 @@
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
     ArtField* f = soa.DecodeField(fid);
-    return soa.AddLocalReference<jobject>(f->GetObject(o));
+    return soa.AddLocalReference<jobject>(f->GetObject(o.Decode()));
   }
 
   static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
@@ -1239,27 +1241,27 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_object);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
-    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
+    ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
     ArtField* f = soa.DecodeField(fid);
-    f->SetObject<false>(o, v);
+    f->SetObject<false>(o.Decode(), v.Decode());
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
     ArtField* f = soa.DecodeField(fid);
-    f->SetObject<false>(f->GetDeclaringClass(), v);
+    f->SetObject<false>(f->GetDeclaringClass(), v.Decode());
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(instance); \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
   ScopedObjectAccess soa(env); \
-  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  return f->Get ##fn (o)
+  return f->Get ##fn (o.Decode())
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
@@ -1271,9 +1273,9 @@
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(instance); \
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
   ScopedObjectAccess soa(env); \
-  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  f->Set ##fn <false>(o, value)
+  f->Set ##fn <false>(o.Decode(), value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
@@ -1657,20 +1659,20 @@
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<mirror::String*>(java_string)->GetLength();
+    return soa.Decode<mirror::String>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
+    return soa.Decode<mirror::String>(java_string)->GetUtfLength();
   }
 
   static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                               jchar* buf) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (start < 0 || length < 0 || length > s->GetLength() - start) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -1690,7 +1692,7 @@
                                  char* buf) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (start < 0 || length < 0 || length > s->GetLength() - start) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -1710,7 +1712,7 @@
   static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(s) || s->IsCompressed()) {
       jchar* chars = new jchar[s->GetLength()];
@@ -1736,7 +1738,7 @@
   static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (s->IsCompressed() || (s->IsCompressed() == false && chars != s->GetValue())) {
       delete[] chars;
     }
@@ -1745,11 +1747,11 @@
   static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(s)) {
       StackHandleScope<1> hs(soa.Self());
-      HandleWrapper<mirror::String> h(hs.NewHandleWrapper(&s));
+      HandleWrapperObjPtr<mirror::String> h(hs.NewHandleWrapper(&s));
       if (!kUseReadBarrier) {
         heap->IncrementDisableMovingGC(soa.Self());
       } else {
@@ -1782,7 +1784,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (heap->IsMovableObject(s)) {
       if (!kUseReadBarrier) {
         heap->DecrementDisableMovingGC(soa.Self());
@@ -1803,7 +1805,7 @@
       *is_copy = JNI_TRUE;
     }
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     size_t byte_count = s->GetUtfLength();
     char* bytes = new char[byte_count + 1];
     CHECK(bytes != nullptr);  // bionic aborts anyway.
@@ -1826,7 +1828,7 @@
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
       soa.Vm()->JniAbortF("GetArrayLength", "not an array: %s", PrettyTypeOf(obj).c_str());
       return 0;
@@ -1838,8 +1840,8 @@
   static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
     CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
-    mirror::ObjectArray<mirror::Object>* array =
-        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
     return soa.AddLocalReference<jobject>(array->Get(index));
   }
 
@@ -1847,10 +1849,10 @@
                                     jobject java_value) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::ObjectArray<mirror::Object>* array =
-        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
-    mirror::Object* value = soa.Decode<mirror::Object*>(java_value);
-    array->Set<false>(index, value);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
+    ObjPtr<mirror::Object> value = soa.Decode<mirror::Object>(java_value);
+    array->Set<false>(index, value.Decode());
   }
 
   static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
@@ -1893,7 +1895,7 @@
     ScopedObjectAccess soa(env);
     mirror::Class* array_class;
     {
-      mirror::Class* element_class = soa.Decode<mirror::Class*>(element_jclass);
+      mirror::Class* element_class = soa.Decode<mirror::Class>(element_jclass).Decode();
       if (UNLIKELY(element_class->IsPrimitive())) {
         soa.Vm()->JniAbortF("NewObjectArray", "not an object type: %s",
                             PrettyDescriptor(element_class).c_str());
@@ -1910,7 +1912,7 @@
     mirror::ObjectArray<mirror::Object>* result =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
     if (result != nullptr && initial_element != nullptr) {
-      mirror::Object* initial_object = soa.Decode<mirror::Object*>(initial_element);
+      ObjPtr<mirror::Object> initial_object = soa.Decode<mirror::Object>(initial_element);
       if (initial_object != nullptr) {
         mirror::Class* element_class = result->GetClass()->GetComponentType();
         if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) {
@@ -1921,7 +1923,7 @@
           return nullptr;
         } else {
           for (jsize i = 0; i < length; ++i) {
-            result->SetWithoutChecks<false>(i, initial_object);
+            result->SetWithoutChecks<false>(i, initial_object.Decode());
           }
         }
       }
@@ -1936,7 +1938,7 @@
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
     if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
       soa.Vm()->JniAbortF("GetPrimitiveArrayCritical", "expected primitive array, given %s",
                           PrettyDescriptor(array->GetClass()).c_str());
@@ -1952,7 +1954,7 @@
         heap->IncrementDisableThreadFlip(soa.Self());
       }
       // Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
-      array = soa.Decode<mirror::Array*>(java_array);
+      array = soa.Decode<mirror::Array>(java_array);
     }
     if (is_copy != nullptr) {
       *is_copy = JNI_FALSE;
@@ -1964,14 +1966,14 @@
                                             jint mode) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
     if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
       soa.Vm()->JniAbortF("ReleasePrimitiveArrayCritical", "expected primitive array, given %s",
                           PrettyDescriptor(array->GetClass()).c_str());
       return;
     }
     const size_t component_size = array->GetClass()->GetComponentSize();
-    ReleasePrimitiveArray(soa, array, component_size, elements, mode);
+    ReleasePrimitiveArray(soa, array.Decode(), component_size, elements, mode);
   }
 
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
@@ -2145,7 +2147,7 @@
     }
     CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     if (UNLIKELY(method_count == 0)) {
       LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for "
           << PrettyDescriptor(c);
@@ -2157,13 +2159,13 @@
       const char* sig = methods[i].signature;
       const void* fnPtr = methods[i].fnPtr;
       if (UNLIKELY(name == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "method name", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(sig == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "method signature", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(fnPtr == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "native function", i, return_errors);
         return JNI_ERR;
       }
       bool is_fast = false;
@@ -2206,17 +2208,17 @@
       // the parent.
       ArtMethod* m = nullptr;
       bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled();
-      for (mirror::Class* current_class = c;
+      for (ObjPtr<mirror::Class> current_class = c;
            current_class != nullptr;
            current_class = current_class->GetSuperClass()) {
         // Search first only comparing methods which are native.
-        m = FindMethod<true>(current_class, name, sig);
+        m = FindMethod<true>(current_class.Decode(), name, sig);
         if (m != nullptr) {
           break;
         }
 
         // Search again comparing to all methods, to find non-native methods that match.
-        m = FindMethod<false>(current_class, name, sig);
+        m = FindMethod<false>(current_class.Decode(), name, sig);
         if (m != nullptr) {
           break;
         }
@@ -2238,14 +2240,14 @@
             << "Failed to register native method "
             << PrettyDescriptor(c) << "." << name << sig << " in "
             << c->GetDexCache()->GetLocation()->ToModifiedUtf8();
-        ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
+        ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
         LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
             << "Failed to register non-native method "
             << PrettyDescriptor(c) << "." << name << sig
             << " as native";
-        ThrowNoSuchMethodError(soa, c, name, sig, "native");
+        ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "native");
         return JNI_ERR;
       }
 
@@ -2260,7 +2262,7 @@
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
 
     VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
 
@@ -2283,24 +2285,24 @@
   static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     o = o->MonitorEnter(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
     }
-    soa.Env()->monitors.Add(o);
+    soa.Env()->monitors.Add(o.Decode());
     return JNI_OK;
   }
 
   static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     o->MonitorExit(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
     }
-    soa.Env()->monitors.Remove(o);
+    soa.Env()->monitors.Remove(o.Decode());
     return JNI_OK;
   }
 
@@ -2409,7 +2411,7 @@
   static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array,
                                            const char* fn_name, const char* operation)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    ArtArrayT* array = soa.Decode<ArtArrayT*>(java_array);
+    ObjPtr<ArtArrayT> array = soa.Decode<ArtArrayT>(java_array);
     if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) {
       soa.Vm()->JniAbortF(fn_name,
                           "attempt to %s %s primitive array elements with an object of type %s",
@@ -2419,7 +2421,7 @@
       return nullptr;
     }
     DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize());
-    return array;
+    return array.Decode();
   }
 
   template <typename ArrayT, typename ElementT, typename ArtArrayT>
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fe0081c..fbd670c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -22,7 +22,7 @@
 #include "java_vm_ext.h"
 #include "jni_env_ext.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 
 namespace art {
@@ -58,7 +58,7 @@
   void ExpectException(jclass exception_class) {
     ScopedObjectAccess soa(env_);
     EXPECT_TRUE(env_->ExceptionCheck())
-        << PrettyDescriptor(soa.Decode<mirror::Class*>(exception_class));
+        << PrettyDescriptor(soa.Decode<mirror::Class>(exception_class));
     jthrowable exception = env_->ExceptionOccurred();
     EXPECT_NE(nullptr, exception);
     env_->ExceptionClear();
@@ -619,7 +619,7 @@
         class_loader_ = LoadDex("MyClassNatives");
         StackHandleScope<1> hs(soa.Self());
         Handle<mirror::ClassLoader> loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
         mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
         const auto pointer_size = class_linker_->GetImagePointerSize();
         ArtMethod* method = direct ? c->FindDirectMethod(method_name, method_sig, pointer_size) :
@@ -679,7 +679,12 @@
   ASSERT_TRUE(env_->IsInstanceOf(o, c));
   // ...whose fields haven't been initialized because
   // we didn't call a constructor.
-  ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+  if (art::mirror::kUseStringCompression) {
+    // Zero-length string is compressed, so the length internally will be -(1 << 31).
+    ASSERT_EQ(-2147483648, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+  } else {
+    ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+  }
 }
 
 TEST_F(JniInternalTest, GetVersion) {
@@ -1598,7 +1603,7 @@
 TEST_F(JniInternalTest, GetStringChars_ReleaseStringChars) {
   jstring s = env_->NewStringUTF("hello");
   ScopedObjectAccess soa(env_);
-  mirror::String* s_m = soa.Decode<mirror::String*>(s);
+  ObjPtr<mirror::String> s_m = soa.Decode<mirror::String>(s);
   ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
@@ -2236,7 +2241,7 @@
 
 static bool IsLocked(JNIEnv* env, jobject jobj) {
   ScopedObjectAccess soa(env);
-  LockWord lock_word = soa.Decode<mirror::Object*>(jobj)->GetLockWord(true);
+  LockWord lock_word = soa.Decode<mirror::Object>(jobj)->GetLockWord(true);
   switch (lock_word.GetState()) {
     case LockWord::kHashCode:
     case LockWord::kUnlocked:
diff --git a/runtime/jobject_comparator.cc b/runtime/jobject_comparator.cc
index 1f424b3..443f095 100644
--- a/runtime/jobject_comparator.cc
+++ b/runtime/jobject_comparator.cc
@@ -19,7 +19,7 @@
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -32,8 +32,8 @@
   }
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object*>(jobj1)));
-  Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object*>(jobj2)));
+  Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object>(jobj1)));
+  Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object>(jobj2)));
   if (obj1.Get() == nullptr) {
     return true;
   } else if (obj2.Get() == nullptr) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 548087e..6c1259b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -54,9 +54,10 @@
 class DexCache;
 class IfTable;
 class Method;
-struct StringDexCachePair;
+template <typename T> struct PACKED(8) DexCachePair;
 
-using StringDexCacheType = std::atomic<mirror::StringDexCachePair>;
+using StringDexCachePair = DexCachePair<mirror::String>;
+using StringDexCacheType = std::atomic<StringDexCachePair>;
 
 // C++ mirror of java.lang.Class
 class MANAGED Class FINAL : public Object {
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 220979a..359462d 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -39,7 +39,7 @@
 
 inline mirror::String* DexCache::GetResolvedString(uint32_t string_idx) {
   DCHECK_LT(string_idx, GetDexFile()->NumStringIds());
-  return StringDexCachePair::LookupString(GetStrings(), string_idx, NumStrings()).Read();
+  return StringDexCachePair::Lookup(GetStrings(), string_idx, NumStrings()).Read();
 }
 
 inline void DexCache::SetResolvedString(uint32_t string_idx, mirror::String* resolved) {
@@ -61,10 +61,10 @@
   DCHECK(Runtime::Current()->IsAotCompiler());
   StringDexCacheType* slot = &GetStrings()[slot_idx];
   // This is racy but should only be called from the transactional interpreter.
-  if (slot->load(std::memory_order_relaxed).string_index == string_idx) {
+  if (slot->load(std::memory_order_relaxed).index == string_idx) {
     StringDexCachePair cleared(
         nullptr,
-        StringDexCachePair::InvalidStringIndexForSlot(slot_idx));
+        StringDexCachePair::InvalidIndexForSlot(slot_idx));
     slot->store(cleared, std::memory_order_relaxed);
   }
 }
@@ -155,11 +155,11 @@
     mirror::StringDexCacheType* strings = GetStrings();
     for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) {
       StringDexCachePair source = strings[i].load(std::memory_order_relaxed);
-      mirror::String* before = source.string_pointer.Read<kReadBarrierOption>();
+      mirror::String* before = source.object.Read<kReadBarrierOption>();
       GcRoot<mirror::String> root(before);
       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
       if (root.Read() != before) {
-        source.string_pointer = GcRoot<String>(root.Read());
+        source.object = GcRoot<String>(root.Read());
         strings[i].store(source, std::memory_order_relaxed);
       }
     }
@@ -175,9 +175,9 @@
   mirror::StringDexCacheType* src = GetStrings();
   for (size_t i = 0, count = NumStrings(); i < count; ++i) {
     StringDexCachePair source = src[i].load(std::memory_order_relaxed);
-    mirror::String* ptr = source.string_pointer.Read<kReadBarrierOption>();
+    mirror::String* ptr = source.object.Read<kReadBarrierOption>();
     mirror::String* new_source = visitor(ptr);
-    source.string_pointer = GcRoot<String>(new_source);
+    source.object = GcRoot<String>(new_source);
     dest[i].store(source, std::memory_order_relaxed);
   }
 }
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 7d4021f..d81dedc 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -35,9 +35,9 @@
 
 class String;
 
-struct PACKED(8) StringDexCachePair {
-  GcRoot<String> string_pointer;
-  uint32_t string_index;
+template <typename T> struct PACKED(8) DexCachePair {
+  GcRoot<T> object;
+  uint32_t index;
   // The array is initially [ {0,0}, {0,0}, {0,0} ... ]
   // We maintain the invariant that once a dex cache entry is populated,
   // the pointer is always non-0
@@ -45,47 +45,51 @@
   // {non-0, non-0} OR {0,0}
   //
   // It's generally sufficiently enough then to check if the
-  // lookup string index matches the stored string index (for a >0 string index)
+  // lookup index matches the stored index (for a >0 lookup index)
   // because if it's true the pointer is also non-null.
   //
   // For the 0th entry which is a special case, the value is either
   // {0,0} (initial state) or {non-0, 0} which indicates
-  // that a valid string is stored at that index for a dex string id of 0.
+  // that a valid object is stored at that index for a dex section id of 0.
   //
-  // As an optimization, we want to avoid branching on the string pointer since
-  // it's always non-null if the string id branch succeeds (except for the 0th string id).
+  // As an optimization, we want to avoid branching on the object pointer since
+  // it's always non-null if the id branch succeeds (except for the 0th id).
   // Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail
-  // the lookup string id == stored id branch.
-  StringDexCachePair(String* string, uint32_t string_idx)
-      : string_pointer(string),
-        string_index(string_idx) {}
-  StringDexCachePair() = default;
-  StringDexCachePair(const StringDexCachePair&) = default;
-  StringDexCachePair& operator=(const StringDexCachePair&) = default;
+  // the lookup id == stored id branch.
+  DexCachePair(T* object, uint32_t index)
+      : object(object),
+        index(index) {}
+  DexCachePair() = default;
+  DexCachePair(const DexCachePair<T>&) = default;
+  DexCachePair& operator=(const DexCachePair<T>&) = default;
 
-  static void Initialize(StringDexCacheType* strings) {
-    mirror::StringDexCachePair first_elem;
-    first_elem.string_pointer = GcRoot<String>(nullptr);
-    first_elem.string_index = InvalidStringIndexForSlot(0);
-    strings[0].store(first_elem, std::memory_order_relaxed);
+  static void Initialize(std::atomic<DexCachePair<T>>* dex_cache) {
+    DexCachePair<T> first_elem;
+    first_elem.object = GcRoot<T>(nullptr);
+    first_elem.index = InvalidIndexForSlot(0);
+    dex_cache[0].store(first_elem, std::memory_order_relaxed);
   }
 
-  static GcRoot<String> LookupString(StringDexCacheType* dex_cache,
-                                     uint32_t string_idx,
-                                     uint32_t cache_size) {
-    StringDexCachePair index_string = dex_cache[string_idx % cache_size]
-        .load(std::memory_order_relaxed);
-    if (string_idx != index_string.string_index) return GcRoot<String>(nullptr);
-    DCHECK(!index_string.string_pointer.IsNull());
-    return index_string.string_pointer;
+  static GcRoot<T> Lookup(std::atomic<DexCachePair<T>>* dex_cache,
+                          uint32_t idx,
+                          uint32_t cache_size) {
+    DexCachePair<T> element = dex_cache[idx % cache_size].load(std::memory_order_relaxed);
+    if (idx != element.index) {
+      return GcRoot<T>(nullptr);
+    }
+
+    DCHECK(!element.object.IsNull());
+    return element.object;
   }
 
-  static uint32_t InvalidStringIndexForSlot(uint32_t slot) {
+  static uint32_t InvalidIndexForSlot(uint32_t slot) {
     // Since the cache size is a power of two, 0 will always map to slot 0.
     // Use 1 for slot 0 and 0 for all other slots.
     return (slot == 0) ? 1u : 0u;
   }
 };
+
+using StringDexCachePair = DexCachePair<mirror::String>;
 using StringDexCacheType = std::atomic<StringDexCachePair>;
 
 // C++ mirror of java.lang.DexCache.
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 43ba362..ac04200 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -24,7 +24,7 @@
 #include "mirror/class_loader-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace mirror {
@@ -56,7 +56,7 @@
   ClassLinker* const class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      soa.Decode<mirror::ClassLoader>(jclass_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LMain;", class_loader);
   ASSERT_TRUE(klass != nullptr);
   LinearAlloc* const linear_alloc = klass->GetClassLoader()->GetAllocator();
@@ -72,7 +72,7 @@
   ClassLinker* const class_linker = runtime->GetClassLinker();
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      soa.Decode<mirror::ClassLoader>(jclass_loader)));
   Handle<mirror::Class> klass1 =
       hs.NewHandle(class_linker->FindClass(soa.Self(), "Lpackage1/Package1;", class_loader));
   ASSERT_TRUE(klass1.Get() != nullptr);
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
new file mode 100644
index 0000000..fdfaaa8
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "method_handle_impl.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodHandleImpl::static_class_;
+
+void MethodHandleImpl::SetClass(Class* klass) {
+  CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+  CHECK(klass != nullptr);
+  static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodHandleImpl::ResetClass() {
+  CHECK(!static_class_.IsNull());
+  static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodHandleImpl::VisitRoots(RootVisitor* visitor) {
+  static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+}  // namespace mirror
+}  // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
new file mode 100644
index 0000000..a0aae3c
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+#define ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+
+#include "class.h"
+#include "gc_root.h"
+#include "object.h"
+#include "method_type.h"
+
+namespace art {
+
+struct MethodHandleImplOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodHandle
+class MANAGED MethodHandle : public Object {
+ public:
+  mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_));
+  }
+
+  ArtMethod* GetTargetMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return reinterpret_cast<ArtMethod*>(
+        GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
+  }
+
+ private:
+  HeapReference<mirror::Object> as_type_cache_;
+  HeapReference<mirror::MethodType> method_type_;
+  uint64_t art_field_or_method_;
+  uint32_t handle_kind_;
+
+ private:
+  static MemberOffset AsTypeCacheOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodHandle, as_type_cache_));
+  }
+  static MemberOffset MethodTypeOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodHandle, method_type_));
+  }
+  static MemberOffset ArtFieldOrMethodOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodHandle, art_field_or_method_));
+  }
+  static MemberOffset HandleKindOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodHandle, handle_kind_));
+  }
+
+  friend struct art::MethodHandleImplOffsets;  // for verifying offset information
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandle);
+};
+
+// C++ mirror of java.lang.invoke.MethodHandleImpl
+class MANAGED MethodHandleImpl : public MethodHandle {
+ public:
+  static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return static_class_.Read();
+  }
+
+  static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+  static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+  static GcRoot<mirror::Class> static_class_;  // java.lang.invoke.MethodHandleImpl.class
+
+  friend struct art::MethodHandleImplOffsets;  // for verifying offset information
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandleImpl);
+};
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
new file mode 100644
index 0000000..ba6ea5e
--- /dev/null
+++ b/runtime/mirror/method_type.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "method_type.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodType::static_class_;
+
+mirror::MethodType* MethodType::Create(Thread* const self,
+                                       Handle<Class> return_type,
+                                       Handle<ObjectArray<Class>> param_types) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::MethodType> mt(
+      hs.NewHandle(static_cast<MethodType*>(StaticClass()->AllocObject(self))));
+
+  // TODO: Do we ever create a MethodType during a transaction ? There doesn't
+  // seem like a good reason to do a polymorphic invoke that results in the
+  // resolution of a method type in an unstarted runtime.
+  mt->SetFieldObject<false>(FormOffset(), nullptr);
+  mt->SetFieldObject<false>(MethodDescriptorOffset(), nullptr);
+  mt->SetFieldObject<false>(RTypeOffset(), return_type.Get());
+  mt->SetFieldObject<false>(PTypesOffset(), param_types.Get());
+  mt->SetFieldObject<false>(WrapAltOffset(), nullptr);
+
+  return mt.Get();
+}
+
+bool MethodType::IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (GetRType() != other->GetRType()) {
+    return false;
+  }
+
+  mirror::ObjectArray<Class>* const p_types = GetPTypes();
+  const int32_t params_length = p_types->GetLength();
+
+  mirror::ObjectArray<Class>* const other_p_types = other->GetPTypes();
+  if (params_length != other_p_types->GetLength()) {
+    return false;
+  }
+
+  for (int32_t i = 0; i < params_length; ++i) {
+    if (p_types->GetWithoutChecks(i) != other_p_types->GetWithoutChecks(i)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void MethodType::SetClass(Class* klass) {
+  CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+  CHECK(klass != nullptr);
+  static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodType::ResetClass() {
+  CHECK(!static_class_.IsNull());
+  static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodType::VisitRoots(RootVisitor* visitor) {
+  static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+}  // namespace mirror
+}  // namespace art
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
new file mode 100644
index 0000000..5b50409
--- /dev/null
+++ b/runtime/mirror/method_type.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+#define ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+
+#include "object.h"
+#include "string.h"
+#include "mirror/object_array.h"
+#include "utils.h"
+
+namespace art {
+
+struct MethodTypeOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodType
+class MANAGED MethodType : public Object {
+ public:
+  static mirror::MethodType* Create(Thread* const self,
+                                    Handle<Class> return_type,
+                                    Handle<ObjectArray<Class>> param_types)
+      REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+  static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return static_class_.Read();
+  }
+
+  ObjectArray<Class>* GetPTypes() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_));
+  }
+
+  Class* GetRType() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_));
+  }
+
+  static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+  static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Returns true iff. |other| is an exact match for this method type, i.e
+  // iff. they have the same return types and parameter types.
+  bool IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+  static MemberOffset FormOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodType, form_));
+  }
+
+  static MemberOffset MethodDescriptorOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodType, method_descriptor_));
+  }
+
+  static MemberOffset PTypesOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodType, p_types_));
+  }
+
+  static MemberOffset RTypeOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodType, r_type_));
+  }
+
+  static MemberOffset WrapAltOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(MethodType, wrap_alt_));
+  }
+
+  HeapReference<mirror::Object> form_;  // Unused in the runtime
+  HeapReference<mirror::String> method_descriptor_;  // Unused in the runtime
+  HeapReference<ObjectArray<mirror::Class>> p_types_;
+  HeapReference<mirror::Class> r_type_;
+  HeapReference<mirror::Object> wrap_alt_;  // Unused in the runtime
+
+  static GcRoot<mirror::Class> static_class_;  // java.lang.invoke.MethodType.class
+
+  friend struct art::MethodTypeOffsets;  // for verifying offset information
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MethodType);
+};
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_RUNTIME_MIRROR_METHOD_TYPE_H_
diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc
new file mode 100644
index 0000000..a968bff
--- /dev/null
+++ b/runtime/mirror/method_type_test.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "method_type.h"
+
+#include <string>
+#include <vector>
+
+#include "class_linker.h"
+#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
+#include "runtime/mirror/class.h"
+#include "runtime/mirror/class_loader.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace mirror {
+
+class MethodTypeTest : public CommonRuntimeTest {};
+
+static std::string FullyQualifiedType(const std::string& shorthand) {
+  return "Ljava/lang/" + shorthand + ";";
+}
+
+static mirror::MethodType* CreateMethodType(const std::string& return_type,
+                                            const std::vector<std::string>& param_types) {
+  CHECK_LT(param_types.size(), 3u);
+
+  Runtime* const runtime = Runtime::Current();
+  ClassLinker* const class_linker = runtime->GetClassLinker();
+  Thread* const self = Thread::Current();
+
+  ScopedObjectAccess soa(self);
+  StackHandleScope<5> hs(soa.Self());
+
+  Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+
+  Handle<mirror::Class> return_clazz = hs.NewHandle(class_linker->FindClass(
+          soa.Self(), FullyQualifiedType(return_type).c_str(), boot_class_loader));
+  CHECK(return_clazz.Get() != nullptr);
+
+  mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+  mirror::Class* class_array_type = class_linker->FindArrayClass(self, &class_type);
+  Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle(
+      mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size()));
+
+  for (uint32_t i = 0; i < param_types.size(); ++i) {
+    Handle<mirror::Class> param = hs.NewHandle(class_linker->FindClass(
+        soa.Self(), FullyQualifiedType(param_types[i]).c_str(), boot_class_loader));
+    param_classes->Set(i, param.Get());
+  }
+
+  return mirror::MethodType::Create(self, return_clazz, param_classes);
+}
+
+
+TEST_F(MethodTypeTest, IsExactMatch) {
+  ScopedObjectAccess soa(Thread::Current());
+  {
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+    Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+    ASSERT_TRUE(mt1->IsExactMatch(mt2.Get()));
+  }
+
+  // Mismatched return type.
+  {
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+    Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("Integer", { "Integer" }));
+    ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+  }
+
+  // Mismatched param types.
+  {
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+    Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+    ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+  }
+
+  // Wrong number of param types.
+  {
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::MethodType> mt1 = hs.NewHandle(
+        CreateMethodType("String", { "String", "String" }));
+    Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+    ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+  }
+}
+
+}  // namespace mirror
+}  // namespace art
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 0f5cbb2..ad7558c 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -31,6 +31,7 @@
 #include "lock_word-inl.h"
 #include "monitor.h"
 #include "object_array-inl.h"
+#include "obj_ptr-inl.h"
 #include "read_barrier-inl.h"
 #include "reference.h"
 #include "runtime.h"
@@ -281,7 +282,7 @@
 }
 
 template<VerifyObjectFlags kVerifyFlags>
-inline bool Object::InstanceOf(Class* klass) {
+inline bool Object::InstanceOf(ObjPtr<Class> klass) {
   DCHECK(klass != nullptr);
   DCHECK(GetClass<kVerifyNone>() != nullptr);
   return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
@@ -509,7 +510,7 @@
         template GetObjectSize<kNewFlags, kReadBarrierOption>();
   }
   DCHECK_GE(result, sizeof(Object))
-      << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
+      << " class=" << PrettyClass(GetClass<kNewFlags, kReadBarrierOption>());
   return result;
 }
 
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 262cb57..10faf60 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -20,6 +20,7 @@
 #include "base/casts.h"
 #include "base/enums.h"
 #include "globals.h"
+#include "obj_ptr.h"
 #include "object_reference.h"
 #include "offsets.h"
 #include "verify_object.h"
@@ -120,7 +121,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool VerifierInstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE bool InstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  ALWAYS_INLINE bool InstanceOf(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index f4ecfb5..40ee3a2 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -38,7 +38,7 @@
 #include "obj_ptr.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "string-inl.h"
 
 namespace art {
@@ -365,7 +365,7 @@
   const DexFile* dex_file = GetFirstDexFile(class_loader);
 
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader>(class_loader)));
   Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader);
   ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
   const DexFile::TypeId* klass_type_id = dex_file->FindTypeId("LStaticsFromCode;");
@@ -495,8 +495,8 @@
   jobject jclass_loader_1 = LoadDex("ProtoCompare");
   jobject jclass_loader_2 = LoadDex("ProtoCompare2");
   StackHandleScope<4> hs(soa.Self());
-  Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_1)));
-  Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_2)));
+  Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_1)));
+  Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_2)));
 
   Class* klass1 = linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1);
   ASSERT_TRUE(klass1 != nullptr);
@@ -538,7 +538,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<3> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
 
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
@@ -575,7 +575,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<1> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
 
@@ -613,7 +613,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<1> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
   ASSERT_TRUE(X != nullptr);
@@ -746,25 +746,25 @@
   ObjPtr<mirror::Object, /*kPoison*/ true> null_ptr;
   EXPECT_TRUE(null_ptr.IsNull());
   EXPECT_TRUE(null_ptr.IsValid());
-  EXPECT_TRUE(null_ptr.Get() == nullptr);
+  EXPECT_TRUE(null_ptr.Decode() == nullptr);
   EXPECT_TRUE(null_ptr == nullptr);
   EXPECT_TRUE(null_ptr == null_ptr);
   EXPECT_FALSE(null_ptr != null_ptr);
   EXPECT_FALSE(null_ptr != nullptr);
   null_ptr.AssertValid();
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Handle<mirror::Class> h_X(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)));
   ObjPtr<Class, /*kPoison*/ true> X(h_X.Get());
   EXPECT_TRUE(!X.IsNull());
   EXPECT_TRUE(X.IsValid());
-  EXPECT_TRUE(X.Get() != nullptr);
-  EXPECT_EQ(h_X.Get(), X.Get());
+  EXPECT_TRUE(X.Decode() != nullptr);
+  EXPECT_EQ(h_X.Get(), X.Decode());
   // FindClass may cause thread suspension, it should invalidate X.
   ObjPtr<Class, /*kPoison*/ true> Y(class_linker_->FindClass(soa.Self(), "LY;", class_loader));
   EXPECT_TRUE(!Y.IsNull());
   EXPECT_TRUE(Y.IsValid());
-  EXPECT_TRUE(Y.Get() != nullptr);
+  EXPECT_TRUE(Y.Decode() != nullptr);
 
   // Should IsNull be safe to call on null ObjPtr? I'll allow it for now.
   EXPECT_TRUE(!X.IsNull());
@@ -773,7 +773,7 @@
   X.Assign(h_X.Get());
   EXPECT_TRUE(!X.IsNull());
   EXPECT_TRUE(X.IsValid());
-  EXPECT_EQ(h_X.Get(), X.Get());
+  EXPECT_EQ(h_X.Get(), X.Decode());
 
   // Allow thread suspension to invalidate Y.
   soa.Self()->AllowThreadSuspension();
@@ -784,7 +784,7 @@
   ObjPtr<mirror::Object, /*kPoison*/ false> unpoisoned;
   EXPECT_TRUE(unpoisoned.IsNull());
   EXPECT_TRUE(unpoisoned.IsValid());
-  EXPECT_TRUE(unpoisoned.Get() == nullptr);
+  EXPECT_TRUE(unpoisoned.Decode() == nullptr);
   EXPECT_TRUE(unpoisoned == nullptr);
   EXPECT_TRUE(unpoisoned == unpoisoned);
   EXPECT_FALSE(unpoisoned != unpoisoned);
@@ -793,7 +793,7 @@
   unpoisoned = h_X.Get();
   EXPECT_FALSE(unpoisoned.IsNull());
   EXPECT_TRUE(unpoisoned == h_X.Get());
-  EXPECT_EQ(unpoisoned.Get(), h_X.Get());
+  EXPECT_EQ(unpoisoned.Decode(), h_X.Get());
 }
 
 }  // namespace mirror
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index fd7a125..dd32df6 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -67,6 +67,7 @@
 
 // Set by the verifier for a method that could not be verified to follow structured locking.
 static constexpr uint32_t kAccMustCountLocks =        0x02000000;  // method (runtime)
+static constexpr uint32_t kAccIntrinsic  =            0x80000000;  // method (runtime)
 
 // Special runtime-only flags.
 // Interface and all its super-interfaces with default methods have been recursively initialized.
@@ -76,6 +77,9 @@
 // class/ancestor overrides finalize()
 static constexpr uint32_t kAccClassIsFinalizable        = 0x80000000;
 
+static constexpr uint32_t kAccFlagsNotUsedByIntrinsic   = 0x007FFFFF;
+static constexpr uint32_t kAccMaxIntrinsic              = 0xFF;
+
 // Valid (meaningful) bits for a field.
 static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
     kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 49b83a7..3bc1b06 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -30,7 +30,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "verifier/method_verifier.h"
diff --git a/runtime/monitor_pool_test.cc b/runtime/monitor_pool_test.cc
index e1837f5..a111c6c 100644
--- a/runtime/monitor_pool_test.cc
+++ b/runtime/monitor_pool_test.cc
@@ -17,7 +17,7 @@
 #include "monitor_pool.h"
 
 #include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index ac6a4f3..4ee46dc 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -27,7 +27,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"  // Strings are easiest to allocate
 #include "object_lock.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_pool.h"
 
 namespace art {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 384de34..0677d5b 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -34,7 +34,7 @@
 #include "oat_file_manager.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "utils.h"
@@ -217,7 +217,7 @@
   bool all_deleted = true;
   {
     ScopedObjectAccess soa(env);
-    mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie);
+    ObjPtr<mirror::Object> dex_files_object = soa.Decode<mirror::Object>(cookie);
     mirror::LongArray* long_dex_files = dex_files_object->AsLongArray();
     // Delete dex files associated with this dalvik.system.DexFile since there should not be running
     // code using it. dex_files is a vector due to multidex.
@@ -277,7 +277,7 @@
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader(
-          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+          hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
       class_linker->RegisterDexFile(*dex_file, class_loader.Get());
       mirror::Class* result = class_linker->DefineClass(soa.Self(),
                                                         descriptor.c_str(),
@@ -287,7 +287,7 @@
                                                         *dex_class_def);
       // Add the used dex file. This only required for the DexFile.loadClass API since normal
       // class loaders already keep their dex files live.
-      class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),
+      class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile).Decode(),
                                                  class_loader.Get());
       if (result != nullptr) {
         VLOG(class_linker) << "DexFile_defineClassNative returning " << result
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index 94933bc..fdced21 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -24,7 +24,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
 #include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 
 namespace art {
@@ -148,7 +148,7 @@
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     StackHandleScope<1> handle_scope(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        handle_scope.NewHandle(soa.Decode<mirror::ClassLoader*>(loader)));
+        handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
     class_linker->RegisterDexFile(*dex_file, class_loader.Get());
     mirror::Class* result = class_linker->DefineClass(
         soa.Self(), class_descriptor, hash, class_loader, *dex_file, *dex_class_def);
@@ -157,7 +157,7 @@
       // InMemoryClassLoader/DexData instance now that a class has
       // been loaded.
       class_linker->InsertDexFileInToClassLoader(
-          soa.Decode<mirror::Object*>(dexData), class_loader.Get());
+          soa.Decode<mirror::Object>(dexData).Decode(), class_loader.Get());
       return soa.AddLocalReference<jclass>(result);
     }
   }
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index f09c067..73c4664 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -36,7 +36,7 @@
 #include "mirror/class.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "trace.h"
 #include "well_known_classes.h"
 
@@ -259,11 +259,11 @@
   ScopedObjectAccess soa(env);
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   // Caller's responsibility to do GC if desired.
-  mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
   if (c == nullptr) {
     return 0;
   }
-  std::vector<mirror::Class*> classes {c};
+  std::vector<mirror::Class*> classes {c.Decode()};
   uint64_t count = 0;
   heap->CountInstances(classes, countAssignable, &count);
   return count;
@@ -274,7 +274,8 @@
   ScopedObjectAccess soa(env);
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   // Caller's responsibility to do GC if desired.
-  auto* decoded_classes = soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaClasses);
+  ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
   if (decoded_classes == nullptr) {
     return nullptr;
   }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index d88c9d4..c7fb44ec 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -46,8 +46,8 @@
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 
@@ -74,7 +74,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   if (UNLIKELY(element_class == nullptr)) {
     ThrowNullPointerException("element class == null");
     return nullptr;
@@ -99,7 +99,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   if (UNLIKELY(element_class == nullptr)) {
     ThrowNullPointerException("element class == null");
     return nullptr;
@@ -122,12 +122,12 @@
     return 0;
   }
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Array* array = soa.Decode<mirror::Array*>(javaArray);
+  ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(javaArray);
   if (!array->IsArrayInstance()) {
     ThrowIllegalArgumentException("not an array");
     return 0;
   }
-  if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
+  if (Runtime::Current()->GetHeap()->IsMovableObject(array.Decode())) {
     ThrowRuntimeException("Trying to get address of movable array object");
     return 0;
   }
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 9da40b9..0dd8cdd 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -22,8 +22,8 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
@@ -31,7 +31,7 @@
 static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   jobject trace = nullptr;
-  if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+  if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
     trace = soa.Self()->CreateInternalStackTrace<false>(soa);
   } else {
     // Suspend thread to build stack trace.
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index fe3cbe7..a78909b 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -24,7 +24,7 @@
 #include "jit/jit.h"
 #include "jni_internal.h"
 #include "JNIHelp.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread-inl.h"
 #include "trace.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index af9b68f..34bd57b 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -33,9 +33,10 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
+#include "obj_ptr-inl.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_thread_state_change-inl.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "utf.h"
@@ -43,10 +44,10 @@
 
 namespace art {
 
-ALWAYS_INLINE static inline mirror::Class* DecodeClass(
+ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
     const ScopedFastNativeObjectAccess& soa, jobject java_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
   DCHECK(c != nullptr);
   DCHECK(c->IsClass());
   // TODO: we could EnsureInitialized here, rather than on every reflective get/set or invoke .
@@ -75,16 +76,19 @@
 
   std::string descriptor(DotToDescriptor(name.c_str()));
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> c(
       hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
   if (c.Get() == nullptr) {
     ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
     env->ExceptionClear();
-    jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
-                                                                  WellKnownClasses::java_lang_ClassNotFoundException_init,
-                                                                  javaName, cause.get()));
+    jthrowable cnfe = reinterpret_cast<jthrowable>(
+        env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
+                       WellKnownClasses::java_lang_ClassNotFoundException_init,
+                       javaName,
+                       cause.get()));
     if (cnfe != nullptr) {
       // Make sure allocation didn't fail with an OOME.
       env->Throw(cnfe);
@@ -100,18 +104,18 @@
 static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  mirror::Class* const c = DecodeClass(soa, javaThis);
+  ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jstring>(mirror::Class::ComputeName(hs.NewHandle(c)));
 }
 
 static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* c = DecodeClass(soa, javaThis);
+  ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
 }
 
 static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
-    Thread* self, mirror::Class* klass, bool public_only, bool force_resolve)
+    Thread* self, ObjPtr<mirror::Class> klass, bool public_only, bool force_resolve)
       REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
   IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields();
@@ -191,8 +195,8 @@
 // Performs a binary search through an array of fields, TODO: Is this fast enough if we don't use
 // the dex cache for lookups? I think CompareModifiedUtf8ToUtf16AsCodePointValues should be fairly
 // fast.
-ALWAYS_INLINE static inline ArtField* FindFieldByName(
-    Thread* self ATTRIBUTE_UNUSED, mirror::String* name, LengthPrefixedArray<ArtField>* fields)
+ALWAYS_INLINE static inline ArtField* FindFieldByName(ObjPtr<mirror::String> name,
+                                                      LengthPrefixedArray<ArtField>* fields)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (fields == nullptr) {
     return nullptr;
@@ -236,14 +240,15 @@
   return nullptr;
 }
 
-ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(
-    Thread* self, mirror::Class* c, mirror::String* name)
+ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(Thread* self,
+                                                            ObjPtr<mirror::Class> c,
+                                                            ObjPtr<mirror::String> name)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* art_field = FindFieldByName(self, name, c->GetIFieldsPtr());
+  ArtField* art_field = FindFieldByName(name, c->GetIFieldsPtr());
   if (art_field != nullptr) {
     return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
   }
-  art_field = FindFieldByName(self, name, c->GetSFieldsPtr());
+  art_field = FindFieldByName(name, c->GetSFieldsPtr());
   if (art_field != nullptr) {
     return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
   }
@@ -251,7 +256,7 @@
 }
 
 static mirror::Field* GetPublicFieldRecursive(
-    Thread* self, mirror::Class* clazz, mirror::String* name)
+    Thread* self, ObjPtr<mirror::Class> clazz, ObjPtr<mirror::String> name)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(clazz != nullptr);
   DCHECK(name != nullptr);
@@ -301,7 +306,7 @@
 
 static jobject Class_getPublicFieldRecursive(JNIEnv* env, jobject javaThis, jstring name) {
   ScopedFastNativeObjectAccess soa(env);
-  auto* name_string = soa.Decode<mirror::String*>(name);
+  auto name_string = soa.Decode<mirror::String>(name);
   if (UNLIKELY(name_string == nullptr)) {
     ThrowNullPointerException("name == null");
     return nullptr;
@@ -312,16 +317,18 @@
 
 static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) {
   ScopedFastNativeObjectAccess soa(env);
-  auto* name_string = soa.Decode<mirror::String*>(name);
-  if (name_string == nullptr) {
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::String> h_string = hs.NewHandle(soa.Decode<mirror::String>(name));
+  if (h_string.Get() == nullptr) {
     ThrowNullPointerException("name == null");
     return nullptr;
   }
-  auto* klass = DecodeClass(soa, javaThis);
-  mirror::Field* result = GetDeclaredField(soa.Self(), klass, name_string);
-  if (result == nullptr) {
-    std::string name_str = name_string->ToModifiedUtf8();
-    if (name_str == "value" && klass->IsStringClass()) {
+  Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
+  Handle<mirror::Field> result =
+      hs.NewHandle(GetDeclaredField(soa.Self(), h_klass.Get(), h_string.Get()));
+  if (result.Get() == nullptr) {
+    std::string name_str = h_string->ToModifiedUtf8();
+    if (name_str == "value" && h_klass->IsStringClass()) {
       // We log the error for this specific case, as the user might just swallow the exception.
       // This helps diagnose crashes when applications rely on the String#value field being
       // there.
@@ -332,11 +339,11 @@
     }
     // We may have a pending exception if we failed to resolve.
     if (!soa.Self()->IsExceptionPending()) {
-      ThrowNoSuchFieldException(DecodeClass(soa, javaThis), name_str.c_str());
+      ThrowNoSuchFieldException(h_klass.Get(), name_str.c_str());
     }
     return nullptr;
   }
-  return soa.AddLocalReference<jobject>(result);
+  return soa.AddLocalReference<jobject>(result.Get());
 }
 
 static jobject Class_getDeclaredConstructorInternal(
@@ -344,11 +351,11 @@
   ScopedFastNativeObjectAccess soa(env);
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
   DCHECK(!Runtime::Current()->IsActiveTransaction());
-  mirror::Constructor* result = mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize,
-                                                                              false>(
+  ObjPtr<mirror::Constructor> result =
+      mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize, false>(
       soa.Self(),
-      DecodeClass(soa, javaThis),
-      soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+      DecodeClass(soa, javaThis).Decode(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
   return soa.AddLocalReference<jobject>(result);
 }
 
@@ -398,9 +405,9 @@
   DCHECK(!Runtime::Current()->IsActiveTransaction());
   mirror::Method* result = mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
       soa.Self(),
-      DecodeClass(soa, javaThis),
-      soa.Decode<mirror::String*>(name),
-      soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+      DecodeClass(soa, javaThis).Decode(),
+      soa.Decode<mirror::String>(name).Decode(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
   return soa.AddLocalReference<jobject>(result);
 }
 
@@ -453,7 +460,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass)));
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationClass)));
   return soa.AddLocalReference<jobject>(
       annotations::GetAnnotationForClass(klass, annotation_class));
 }
@@ -464,10 +471,12 @@
   Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     // Return an empty array instead of a null pointer.
-    mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    ObjPtr<mirror::Class>  annotation_array_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
     mirror::ObjectArray<mirror::Object>* empty_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
+                                                   annotation_array_class.Decode(),
+                                                   0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass));
@@ -519,8 +528,8 @@
   }
   mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
-    if (method->GetClass() ==
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) ==
+        method->GetClass()) {
       return soa.AddLocalReference<jobject>(method);
     }
   }
@@ -536,8 +545,8 @@
   }
   mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
-    if (method->GetClass() ==
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) ==
+        method->GetClass()) {
       return soa.AddLocalReference<jobject>(method);
     }
   }
@@ -598,7 +607,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return false;
   }
-  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsClassAnnotationPresent(klass, annotation_class);
 }
 
@@ -669,7 +678,10 @@
       caller.Assign(GetCallingClass(soa.Self(), 1));
     }
     if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(
-        receiver.Get(), declaring_class, constructor->GetAccessFlags(), caller.Get()))) {
+        MakeObjPtr(receiver.Get()),
+        MakeObjPtr(declaring_class),
+        constructor->GetAccessFlags(),
+        MakeObjPtr(caller.Get())))) {
       soa.Self()->ThrowNewExceptionF(
           "Ljava/lang/IllegalAccessException;", "%s is not accessible from %s",
           PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str());
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index f0140a3..5efafe7 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -21,14 +21,14 @@
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
 
 static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   // Should only be called while holding the lock on the dex cache.
   DCHECK_EQ(dex_cache->GetLockOwnerThreadId(), soa.Self()->GetThreadId());
   const DexFile* dex_file = dex_cache->GetDexFile();
@@ -51,14 +51,14 @@
 
 static jobject DexCache_getResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
   return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
 }
 
 static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
   return soa.AddLocalReference<jobject>(dex_cache->GetResolvedString(string_index));
 }
@@ -66,17 +66,17 @@
 static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index,
                                      jobject type) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
-  dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class*>(type));
+  dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type).Decode());
 }
 
 static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
                                        jobject string) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
-  dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String*>(string));
+  dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String>(string).Decode());
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index 2a36059..6493865 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -18,39 +18,35 @@
 
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 
 namespace art {
 
 static jobject Object_internalClone(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_this);
   return soa.AddLocalReference<jobject>(o->Clone(soa.Self()));
 }
 
 static void Object_notify(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Notify(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->Notify(soa.Self());
 }
 
 static void Object_notifyAll(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->NotifyAll(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self());
 }
 
 static void Object_wait(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Wait(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->Wait(soa.Self());
 }
 
 static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Wait(soa.Self(), ms, ns);
+  soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index aa64b79..b3a967d 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -22,8 +22,8 @@
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "mirror/string-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "verify_object-inl.h"
 
@@ -31,7 +31,7 @@
 
 static jchar String_charAt(JNIEnv* env, jobject java_this, jint index) {
   ScopedFastNativeObjectAccess soa(env);
-  return soa.Decode<mirror::String*>(java_this)->CharAt(index);
+  return soa.Decode<mirror::String>(java_this)->CharAt(index);
 }
 
 static jint String_compareTo(JNIEnv* env, jobject java_this, jobject java_rhs) {
@@ -40,7 +40,8 @@
     ThrowNullPointerException("rhs == null");
     return -1;
   } else {
-    return soa.Decode<mirror::String*>(java_this)->CompareTo(soa.Decode<mirror::String*>(java_rhs));
+    return soa.Decode<mirror::String>(java_this)->CompareTo(
+        soa.Decode<mirror::String>(java_rhs).Decode());
   }
 }
 
@@ -51,8 +52,8 @@
     return nullptr;
   }
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
-  Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String*>(java_string_arg)));
+  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
+  Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String>(java_string_arg)));
   int32_t length_this = string_this->GetLength();
   int32_t length_arg = string_arg->GetLength();
   if (length_arg > 0 && length_this > 0) {
@@ -67,13 +68,13 @@
   ScopedFastNativeObjectAccess soa(env);
   // This method does not handle supplementary characters. They're dealt with in managed code.
   DCHECK_LE(ch, 0xffff);
-  return soa.Decode<mirror::String*>(java_this)->FastIndexOf(ch, start);
+  return soa.Decode<mirror::String>(java_this)->FastIndexOf(ch, start);
 }
 
 static jstring String_fastSubstring(JNIEnv* env, jobject java_this, jint start, jint length) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
+  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), length, string_this,
                                                                  start, allocator_type);
@@ -84,25 +85,24 @@
                                    jcharArray buffer, jint index) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(buffer)));
-  soa.Decode<mirror::String*>(java_this)->GetChars(start, end, char_array, index);
+  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(buffer)));
+  soa.Decode<mirror::String>(java_this)->GetChars(start, end, char_array, index);
 }
 
 static jstring String_intern(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::String* s = soa.Decode<mirror::String*>(java_this);
-  mirror::String* result = s->Intern();
+  ObjPtr<mirror::String> result = soa.Decode<mirror::String>(java_this)->Intern();
   return soa.AddLocalReference<jstring>(result);
 }
 
 static void String_setCharAt(JNIEnv* env, jobject java_this, jint index, jchar c) {
   ScopedFastNativeObjectAccess soa(env);
-  soa.Decode<mirror::String*>(java_this)->SetCharAt(index, c);
+  soa.Decode<mirror::String>(java_this)->SetCharAt(index, c);
 }
 
 static jcharArray String_toCharArray(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::String* s = soa.Decode<mirror::String*>(java_this);
+  ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_this);
   return soa.AddLocalReference<jcharArray>(s->ToCharArray(soa.Self()));
 }
 
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 5a219ef..119f2b8 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -20,8 +20,8 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 
@@ -35,7 +35,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray*>(java_data)));
+  Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray>(java_data)));
   int32_t data_size = byte_array->GetLength();
   if ((offset | byte_count) < 0 || byte_count > data_size - offset) {
     soa.Self()->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;",
@@ -56,7 +56,7 @@
   DCHECK(java_data != nullptr);
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(java_data)));
+  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(java_data)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromCharArray<true>(soa.Self(), char_count,
                                                                     char_array, offset,
@@ -71,7 +71,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(to_copy)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(to_copy)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), string->GetLength(),
                                                                  string, 0, allocator_type);
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 1b399aa..8b9d0c7 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
@@ -60,14 +60,14 @@
   }
 
   // Make sure source and destination are both arrays.
-  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
+  ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
   if (UNLIKELY(!srcObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("source", srcObject);
+    ThrowArrayStoreException_NotAnArray("source", srcObject.Decode());
     return;
   }
-  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+  ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
   if (UNLIKELY(!dstObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("destination", dstObject);
+    ThrowArrayStoreException_NotAnArray("destination", dstObject.Decode());
     return;
   }
   mirror::Array* srcArray = srcObject->AsArray();
@@ -164,8 +164,8 @@
 inline void System_arraycopyTUnchecked(JNIEnv* env, jobject javaSrc, jint srcPos,
                                        jobject javaDst, jint dstPos, jint count) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
-  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+  ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
+  ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
   DCHECK(dstObject != nullptr);
   mirror::Array* srcArray = srcObject->AsArray();
   mirror::Array* dstArray = dstObject->AsArray();
@@ -228,7 +228,7 @@
     return 0;
   }
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(javaObject);
   return static_cast<jint>(o->IdentityHashCode());
 }
 
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index a742e81..0635261 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -20,8 +20,8 @@
 #include "jni_internal.h"
 #include "monitor.h"
 #include "mirror/object.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -109,14 +109,14 @@
 
 static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) {
   ScopedObjectAccess soa(env);
-  mirror::Object* object = soa.Decode<mirror::Object*>(java_object);
+  ObjPtr<mirror::Object> object = soa.Decode<mirror::Object>(java_object);
   if (object == nullptr) {
     ThrowNullPointerException("object == null");
     return JNI_FALSE;
   }
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Thread* thread = Thread::FromManagedThread(soa, java_thread);
-  return thread->HoldsLock(object);
+  return thread->HoldsLock(object.Decode());
 }
 
 static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
@@ -132,7 +132,7 @@
   ScopedUtfChars name(env, java_name);
   {
     ScopedObjectAccess soa(env);
-    if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+    if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
       soa.Self()->SetThreadName(name.c_str());
       return;
     }
@@ -172,8 +172,8 @@
 
 static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* lock = soa.Decode<mirror::Object*>(java_lock);
-  Monitor::Wait(Thread::Current(), lock, ms, ns, true, kSleeping);
+  ObjPtr<mirror::Object> lock = soa.Decode<mirror::Object>(java_lock);
+  Monitor::Wait(Thread::Current(), lock.Decode(), ms, ns, true, kSleeping);
 }
 
 /*
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index cb8a869..ff3e044 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -17,7 +17,7 @@
 #include "java_lang_Throwable.h"
 
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 6f735aa..0694c4d 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -20,7 +20,7 @@
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedUtfChars.h"
 #include "zip_archive.h"
 
@@ -29,7 +29,7 @@
 static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
                                             jstring javaName) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+  ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(javaLoader);
   ScopedUtfChars name(env, javaName);
   if (name.c_str() == nullptr) {
     return nullptr;
@@ -37,7 +37,10 @@
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
   std::string descriptor(DotToDescriptor(name.c_str()));
   const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
-  mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
+  mirror::Class* c = cl->LookupClass(soa.Self(),
+                                     descriptor.c_str(),
+                                     descriptor_hash,
+                                     loader.Decode());
   if (c != nullptr && c->IsResolved()) {
     return soa.AddLocalReference<jclass>(c);
   }
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index 0532c35..08bcc38 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -21,14 +21,15 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
 static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::FinalizerReference* const ref = soa.Decode<mirror::FinalizerReference*>(javaThis);
-  return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(ref);
+  ObjPtr<mirror::FinalizerReference> ref = soa.Decode<mirror::FinalizerReference>(javaThis);
+  return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(
+      ref.Decode());
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index d232059..9a088ed 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -21,15 +21,15 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
 static jobject Reference_getReferent(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Reference* const ref = soa.Decode<mirror::Reference*>(javaThis);
+  ObjPtr<mirror::Reference> ref = soa.Decode<mirror::Reference>(javaThis);
   mirror::Object* const referent =
-      Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref);
+      Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref.Decode());
   return soa.AddLocalReference<jobject>(referent);
 }
 
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index beb953b..3718ce8 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -22,7 +22,7 @@
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "handle_scope-inl.h"
 
 namespace art {
@@ -32,15 +32,15 @@
   ScopedFastNativeObjectAccess soa(env);
   DCHECK(javaElementClass != nullptr);
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class*>(javaElementClass)));
+  Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class>(javaElementClass)));
   DCHECK(element_class->IsClass());
   DCHECK(javaDimArray != nullptr);
-  mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
+  ObjPtr<mirror::Object> dimensions_obj = soa.Decode<mirror::Object>(javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
   DCHECK_EQ(dimensions_obj->GetClass()->GetComponentType()->GetPrimitiveType(),
             Primitive::kPrimInt);
   Handle<mirror::IntArray> dimensions_array(
-      hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj)));
+      hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj.Decode())));
   mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
                                                              dimensions_array);
   return soa.AddLocalReference<jobject>(new_array);
@@ -53,7 +53,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
   mirror::Class* array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index d001d0c..7de0147 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -26,7 +26,7 @@
 #include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -60,7 +60,7 @@
  */
 static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Constructor* m = soa.Decode<mirror::Constructor*>(javaMethod);
+  ObjPtr<mirror::Constructor> m = soa.Decode<mirror::Constructor>(javaMethod);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
   if (UNLIKELY(c->IsAbstract())) {
@@ -73,7 +73,7 @@
   if (!m->IsAccessible() && !c->IsPublic()) {
     // Go 2 frames back, this method is always called from newInstance0, which is called from
     // Constructor.newInstance(Object... args).
-    auto* caller = GetCallingClass(soa.Self(), 2);
+    ObjPtr<mirror::Class> caller = GetCallingClass(soa.Self(), 2);
     // If caller is null, then we called from JNI, just avoid the check since JNI avoids most
     // access checks anyways. TODO: Investigate if this the correct behavior.
     if (caller != nullptr && !caller->CanAccess(c.Get())) {
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index f345c09..c7c8008 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -25,7 +25,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -35,10 +35,10 @@
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
     // Return an empty array instead of a null pointer.
-    mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
-    mirror::ObjectArray<mirror::Object>* empty_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+    ObjPtr<mirror::Class> annotation_array_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Decode(), 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
@@ -53,7 +53,7 @@
   if (method->IsProxyMethod()) {
     return nullptr;
   } else {
-    Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+    Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
     return soa.AddLocalReference<jobject>(annotations::GetAnnotationForMethod(method, klass));
   }
 }
@@ -84,7 +84,7 @@
   Thread* self = soa.Self();
   StackHandleScope<8> hs(self);
 
-  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method>(javaMethod));
   ArtMethod* art_method = executable.Get()->GetArtMethod();
   if (art_method->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
@@ -122,7 +122,7 @@
   // Instantiate a Parameter[] to hold the result.
   Handle<mirror::Class> parameter_array_class =
       hs.NewHandle(
-          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+          soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter__array));
   Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
       hs.NewHandle(
           mirror::ObjectArray<mirror::Object>::Alloc(self,
@@ -134,7 +134,7 @@
   }
 
   Handle<mirror::Class> parameter_class =
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter));
   ArtMethod* parameter_init =
       soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
 
@@ -186,7 +186,7 @@
     return false;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsMethodAnnotationPresent(method, klass);
 }
 
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 412445f..2519225 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -25,7 +25,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/field.h"
 #include "reflection-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -43,9 +43,13 @@
                     PrettyClass(field->GetDeclaringClass()).c_str()).c_str());
     return false;
   }
-  mirror::Class* calling_class = nullptr;
-  if (!VerifyAccess(self, obj, field->GetDeclaringClass(), field->GetAccessFlags(),
-                    &calling_class, 1)) {
+  ObjPtr<mirror::Class> calling_class;
+  if (!VerifyAccess(self,
+                    MakeObjPtr(obj),
+                    MakeObjPtr(field->GetDeclaringClass()),
+                    field->GetAccessFlags(),
+                    &calling_class,
+                    1)) {
     ThrowIllegalAccessException(
             StringPrintf("Class %s cannot access %s field %s of class %s",
                 calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -123,8 +127,8 @@
     *class_or_rcvr = declaringClass;
     return true;
   }
-  *class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
-  if (!VerifyObjectIsClass(*class_or_rcvr, declaringClass)) {
+  *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr).Decode();
+  if (!VerifyObjectIsClass(MakeObjPtr(*class_or_rcvr), MakeObjPtr(declaringClass))) {
     DCHECK(soa.Self()->IsExceptionPending());
     return false;
   }
@@ -133,7 +137,7 @@
 
 static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     DCHECK(soa.Self()->IsExceptionPending());
@@ -152,14 +156,14 @@
     DCHECK(soa.Self()->IsExceptionPending());
     return nullptr;
   }
-  return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
+  return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value).Decode());
 }
 
 template<Primitive::Type kPrimitiveType>
 ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaField,
                                                      jobject javaObj) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     DCHECK(soa.Self()->IsExceptionPending());
@@ -303,7 +307,7 @@
 
 static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   // Check that the receiver is non-null and an instance of the field's declaring class.
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
@@ -321,9 +325,12 @@
   }
   // We now don't expect suspension unless an exception is thrown.
   // Unbox the value, if necessary.
-  mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
+  ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
   JValue unboxed_value;
-  if (!UnboxPrimitiveForField(boxed_value, field_type, f->GetArtField(), &unboxed_value)) {
+  if (!UnboxPrimitiveForField(boxed_value,
+                              MakeObjPtr(field_type),
+                              f->GetArtField(),
+                              &unboxed_value)) {
     DCHECK(soa.Self()->IsExceptionPending());
     return;
   }
@@ -339,7 +346,7 @@
 static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
                               const JValue& new_value) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     return;
@@ -419,21 +426,22 @@
 static jobject Field_getAnnotationNative(JNIEnv* env, jobject javaField, jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
   }
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
 }
 
 static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
   ScopedFastNativeObjectAccess soa(env);
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     // Return an empty array instead of a null pointer.
     mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+        soa.Decode<mirror::Class>(
+            WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
     mirror::ObjectArray<mirror::Object>* empty_array =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
@@ -443,7 +451,7 @@
 
 static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
   ScopedFastNativeObjectAccess soa(env);
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
   }
@@ -454,11 +462,11 @@
                                                 jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return false;
   }
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsFieldAnnotationPresent(field, klass);
 }
 
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index b8efb14..b5f2f7c 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -26,7 +26,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index c2a803c..6060b8a 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -21,7 +21,7 @@
 #include "dex_file-inl.h"
 #include "dex_file_annotations.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -53,7 +53,7 @@
   }
 
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return soa.AddLocalReference<jobject>(
       annotations::GetAnnotationForMethodParameter(method, parameterIndex, klass));
 }
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 4a6ab40..ece0338 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -21,7 +21,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/object_array.h"
 #include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "verify_object-inl.h"
 
 namespace art {
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index 64d56f6..2590452 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -18,7 +18,7 @@
 #include "mirror/string.h"
 #include "mirror/string-inl.h"
 #include "native/libcore_util_CharsetUtils.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedPrimitiveArray.h"
 #include "unicode/utf16.h"
 
@@ -154,7 +154,7 @@
                                jchar maxValidChar) {
   ScopedObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
   if (string.Get() == nullptr) {
     return nullptr;
   }
@@ -191,7 +191,7 @@
                                            jint length) {
   ScopedObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
   if (string.Get() == nullptr) {
     return nullptr;
   }
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 0ab2979..5356498 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -19,7 +19,7 @@
 #include "base/logging.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedPrimitiveArray.h"
 
 namespace art {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 9ed0e7e..ca17c26 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -20,7 +20,7 @@
 #include "base/mutex.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "thread_list.h"
diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h
new file mode 100644
index 0000000..1d73813
--- /dev/null
+++ b/runtime/native/scoped_fast_native_object_access-inl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+#define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+
+#include "scoped_fast_native_object_access.h"
+
+#include "art_method-inl.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+inline ScopedFastNativeObjectAccess::ScopedFastNativeObjectAccess(JNIEnv* env)
+    : ScopedObjectAccessAlreadyRunnable(env) {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
+  // Don't work with raw objects in non-runnable states.
+  DCHECK_EQ(Self()->GetState(), kRunnable);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index c4a33df..6a9365d 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,7 +17,8 @@
 #ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 #define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 
-#include "art_method-inl.h"
+#include <jni.h>
+
 #include "scoped_thread_state_change.h"
 
 namespace art {
@@ -26,18 +27,11 @@
 // JNI methods.
 class ScopedFastNativeObjectAccess : public ScopedObjectAccessAlreadyRunnable {
  public:
-  explicit ScopedFastNativeObjectAccess(JNIEnv* env)
+  ALWAYS_INLINE explicit ScopedFastNativeObjectAccess(JNIEnv* env)
     REQUIRES(!Locks::thread_suspend_count_lock_)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-     : ScopedObjectAccessAlreadyRunnable(env) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
-    // Don't work with raw objects in non-runnable states.
-    DCHECK_EQ(Self()->GetState(), kRunnable);
-  }
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
 
-  ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-  }
+  ALWAYS_INLINE ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ScopedFastNativeObjectAccess);
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 472340c..2fae3cc 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -21,7 +21,7 @@
 #include "mirror/array.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -33,61 +33,64 @@
 static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                          jint expectedValue, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                    expectedValue, newValue);
+                                                                    expectedValue,
+                                                                    newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                           jlong expectedValue, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   bool success = obj->CasFieldStrongSequentiallyConsistent64<false>(MemberOffset(offset),
-                                                                    expectedValue, newValue);
+                                                                    expectedValue,
+                                                                    newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                             jobject javaExpectedValue, jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> expectedValue = soa.Decode<mirror::Object>(javaExpectedValue);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
   if (kUseReadBarrier) {
     // Need to make sure the reference stored in the field is a to-space one before attempting the
     // CAS or the CAS could fail incorrectly.
     mirror::HeapReference<mirror::Object>* field_addr =
         reinterpret_cast<mirror::HeapReference<mirror::Object>*>(
-            reinterpret_cast<uint8_t*>(obj) + static_cast<size_t>(offset));
+            reinterpret_cast<uint8_t*>(obj.Decode()) + static_cast<size_t>(offset));
     ReadBarrier::Barrier<mirror::Object, kWithReadBarrier, /*kAlwaysUpdateField*/true>(
-        obj,
+        obj.Decode(),
         MemberOffset(offset),
         field_addr);
   }
   bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset),
-                                                                        expectedValue, newValue);
+                                                                        expectedValue.Decode(),
+                                                                        newValue.Decode());
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jint Unsafe_getInt(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField32(MemberOffset(offset));
 }
 
 static jint Unsafe_getIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField32Volatile(MemberOffset(offset));
 }
 
 static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField32<false>(MemberOffset(offset), newValue);
 }
@@ -95,7 +98,7 @@
 static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                   jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField32Volatile<false>(MemberOffset(offset), newValue);
 }
@@ -103,7 +106,7 @@
 static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                  jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
   obj->SetField32<false>(MemberOffset(offset), newValue);
@@ -111,19 +114,19 @@
 
 static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField64(MemberOffset(offset));
 }
 
 static jlong Unsafe_getLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField64Volatile(MemberOffset(offset));
 }
 
 static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField64<false>(MemberOffset(offset), newValue);
 }
@@ -131,7 +134,7 @@
 static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                    jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField64Volatile<false>(MemberOffset(offset), newValue);
 }
@@ -139,7 +142,7 @@
 static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                   jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
   obj->SetField64<false>(MemberOffset(offset), newValue);
@@ -147,56 +150,56 @@
 
 static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
   return soa.AddLocalReference<jobject>(value);
 }
 
 static jobject Unsafe_getObject(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
   return soa.AddLocalReference<jobject>(value);
 }
 
 static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                              jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
-  obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                      jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
-  obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                     jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
-  obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+  ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
   Primitive::Type primitive_type = component->GetPrimitiveType();
   return mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value();
 }
 
 static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobject component_class) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+  ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
   Primitive::Type primitive_type = component->GetPrimitiveType();
   return Primitive::ComponentSize(primitive_type);
 }
@@ -289,16 +292,16 @@
 
 static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe ATTRIBUTE_UNUSED, jlong src,
                               jlong dst, jlong size) {
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ScopedFastNativeObjectAccess soa(env);
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ScopedFastNativeObjectAccess soa(env);
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
 }
 
 template<typename T>
@@ -306,12 +309,12 @@
                         size_t array_offset,
                         size_t size)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-    const T* src = reinterpret_cast<T*>(srcAddr);
-    size_t sz = size / sizeof(T);
-    size_t of = array_offset / sizeof(T);
-    for (size_t i = 0; i < sz; ++i) {
-        array->Set(i + of, *(src + i));
-    }
+  const T* src = reinterpret_cast<T*>(srcAddr);
+  size_t sz = size / sizeof(T);
+  size_t of = array_offset / sizeof(T);
+  for (size_t i = 0; i < sz; ++i) {
+    array->Set(i + of, *(src + i));
+  }
 }
 
 template<typename T>
@@ -319,12 +322,12 @@
                           size_t array_offset,
                           size_t size)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-    T* dst = reinterpret_cast<T*>(dstAddr);
-    size_t sz = size / sizeof(T);
-    size_t of = array_offset / sizeof(T);
-    for (size_t i = 0; i < sz; ++i) {
-        *(dst + i) = array->Get(i + of);
-    }
+  T* dst = reinterpret_cast<T*>(dstAddr);
+  size_t sz = size / sizeof(T);
+  size_t of = array_offset / sizeof(T);
+  for (size_t i = 0; i < sz; ++i) {
+    *(dst + i) = array->Get(i + of);
+  }
 }
 
 static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env,
@@ -333,29 +336,29 @@
                                               jobject dstObj,
                                               jlong dstOffset,
                                               jlong size) {
-    ScopedObjectAccess soa(env);
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    size_t dst_offset = (size_t)dstOffset;
-    mirror::Object* dst = soa.Decode<mirror::Object*>(dstObj);
-    mirror::Class* component_type = dst->GetClass()->GetComponentType();
-    if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
-        copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
-        copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
-        copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
-        copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
-    } else {
-        ThrowIllegalAccessException("not a primitive array");
-    }
+  ScopedObjectAccess soa(env);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  size_t dst_offset = (size_t)dstOffset;
+  ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj);
+  mirror::Class* component_type = dst->GetClass()->GetComponentType();
+  if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+    copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+    copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+    copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+    copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
+  } else {
+    ThrowIllegalAccessException("not a primitive array");
+  }
 }
 
 static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env,
@@ -364,85 +367,85 @@
                                                 jlong srcOffset,
                                                 jlong dstAddr,
                                                 jlong size) {
-    ScopedObjectAccess soa(env);
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    size_t src_offset = (size_t)srcOffset;
-    mirror::Object* src = soa.Decode<mirror::Object*>(srcObj);
-    mirror::Class* component_type = src->GetClass()->GetComponentType();
-    if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
-        copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
-        copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
-        copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
-        copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
-    } else {
-        ThrowIllegalAccessException("not a primitive array");
-    }
+  ScopedObjectAccess soa(env);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  size_t src_offset = (size_t)srcOffset;
+  ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj);
+  mirror::Class* component_type = src->GetClass()->GetComponentType();
+  if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+    copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+    copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+    copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+    copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
+  } else {
+    ThrowIllegalAccessException("not a primitive array");
+  }
 }
 static jboolean Unsafe_getBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldBoolean(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldBoolean(MemberOffset(offset));
 }
 
 static void Unsafe_putBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset, jboolean newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode (SetField8 is non-transactional).
-    obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode (SetField8 is non-transactional).
+  obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
 }
 
 static jbyte Unsafe_getByte(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldByte(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldByte(MemberOffset(offset));
 }
 
 static void Unsafe_putByte(JNIEnv* env, jobject, jobject javaObj, jlong offset, jbyte newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldByte<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldByte<false>(MemberOffset(offset), newValue);
 }
 
 static jchar Unsafe_getChar(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldChar(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldChar(MemberOffset(offset));
 }
 
 static void Unsafe_putChar(JNIEnv* env, jobject, jobject javaObj, jlong offset, jchar newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldChar<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldChar<false>(MemberOffset(offset), newValue);
 }
 
 static jshort Unsafe_getShort(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldShort(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldShort(MemberOffset(offset));
 }
 
 static void Unsafe_putShort(JNIEnv* env, jobject, jobject javaObj, jlong offset, jshort newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldShort<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldShort<false>(MemberOffset(offset), newValue);
 }
 
 static jfloat Unsafe_getFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int32_t val; jfloat converted;} conv;
   conv.val = obj->GetField32(MemberOffset(offset));
   return conv.converted;
@@ -450,7 +453,7 @@
 
 static void Unsafe_putFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset, jfloat newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int32_t converted; jfloat val;} conv;
   conv.val = newValue;
   // JNI must use non transactional mode.
@@ -459,7 +462,7 @@
 
 static jdouble Unsafe_getDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int64_t val; jdouble converted;} conv;
   conv.val = obj->GetField64(MemberOffset(offset));
   return conv.converted;
@@ -467,7 +470,7 @@
 
 static void Unsafe_putDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset, jdouble newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int64_t converted; jdouble val;} conv;
   conv.val = newValue;
   // JNI must use non transactional mode.
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index 155c008..059dc5a 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -26,7 +26,7 @@
 #include "base/macros.h"
 #include "dex_file-inl.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "sigchain.h"
 
 namespace art {
@@ -43,7 +43,7 @@
   }
 
   ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
 
   uint32_t native_method_count = 0;
   for (auto& m : c->GetMethods(kRuntimePointerSize)) {
@@ -58,7 +58,7 @@
     return 0;
   }
   ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
 
   uint32_t count = 0;
   for (auto& m : c->GetMethods(kRuntimePointerSize)) {
diff --git a/runtime/oat.h b/runtime/oat.h
index 12a8298..4d8687c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '8', '7', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '8', '9', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 415f991..ff00451 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -27,7 +27,7 @@
 #include "oat.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 
 namespace art {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 6ec5e55..d18e946 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -33,7 +33,7 @@
 #include "oat_file_assistant.h"
 #include "oat_file_manager.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 6d4b2f6..acad2a9 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -30,7 +30,7 @@
 #include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
 #include "oat_file_assistant.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
@@ -294,8 +294,8 @@
   }
 
   // Unsupported class-loader?
-  if (class_loader->GetClass() !=
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+  if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+      class_loader->GetClass()) {
     VLOG(class_linker) << "Unsupported class-loader " << PrettyClass(class_loader->GetClass());
     return false;
   }
@@ -338,10 +338,10 @@
   ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
   ArtField* const dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
-  const mirror::Class* const element_class = soa.Decode<mirror::Class*>(
+  ObjPtr<mirror::Class> const element_class = soa.Decode<mirror::Class>(
       WellKnownClasses::dalvik_system_DexPathList__Element);
-  const mirror::Class* const dexfile_class = soa.Decode<mirror::Class*>(
-        WellKnownClasses::dalvik_system_DexFile);
+  ObjPtr<mirror::Class> const dexfile_class = soa.Decode<mirror::Class>(
+      WellKnownClasses::dalvik_system_DexFile);
 
   // Collect all the dex files.
   auto GetDexFilesFn = [&] (const DexFile* cp_dex_file)
@@ -361,9 +361,9 @@
     // We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
 
     mirror::Object* dex_file;
-    if (element->GetClass() == element_class) {
+    if (element_class == element->GetClass()) {
       dex_file = dex_file_field->GetObject(element);
-    } else if (element->GetClass() == dexfile_class) {
+    } else if (dexfile_class == element->GetClass()) {
       dex_file = element;
     } else {
       LOG(WARNING) << "Unsupported element in dex_elements: " << PrettyClass(element->GetClass());
@@ -442,9 +442,9 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::ClassLoader> h_class_loader =
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
     Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
-        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements));
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
     if (h_class_loader.Get() != nullptr &&
         GetDexFilesFromClassLoader(soa, h_class_loader.Get(), &queue)) {
       class_loader_ok = true;
@@ -638,7 +638,7 @@
         ScopedObjectAccess soa(self);
         StackHandleScope<1> hs(self);
         Handle<mirror::ClassLoader> h_loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
         // Can not load app image without class loader.
         if (h_loader.Get() != nullptr) {
           std::string temp_error_msg;
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index a88553c..b416b9d 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -21,7 +21,7 @@
 #include <gtest/gtest.h>
 
 #include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
index 0ab2bfe..a68d9f8 100644
--- a/runtime/oat_quick_method_header.cc
+++ b/runtime/oat_quick_method_header.cc
@@ -17,7 +17,7 @@
 #include "oat_quick_method_header.h"
 
 #include "art_method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
new file mode 100644
index 0000000..1c698b5
--- /dev/null
+++ b/runtime/obj_ptr-inl.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_RUNTIME_OBJ_PTR_INL_H_
+#define ART_RUNTIME_OBJ_PTR_INL_H_
+
+#include "obj_ptr.h"
+#include "thread-inl.h"
+
+namespace art {
+
+template<class MirrorType, bool kPoison>
+inline bool ObjPtr<MirrorType, kPoison>::IsValid() const {
+  if (!kPoison || IsNull()) {
+    return true;
+  }
+  return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+}
+
+template<class MirrorType, bool kPoison>
+inline void ObjPtr<MirrorType, kPoison>::AssertValid() const {
+  if (kPoison) {
+    CHECK(IsValid()) << "Stale object pointer " << DecodeUnchecked() << " , expected cookie "
+        << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
+  }
+}
+
+template<class MirrorType, bool kPoison>
+inline uintptr_t ObjPtr<MirrorType, kPoison>::Encode(MirrorType* ptr) {
+  uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
+  DCHECK_ALIGNED(ref, kObjectAlignment);
+  if (kPoison && ref != 0) {
+    DCHECK_LE(ref, 0xFFFFFFFFU);
+    ref >>= kObjectAlignmentShift;
+    // Put cookie in high bits.
+    Thread* self = Thread::Current();
+    DCHECK(self != nullptr);
+    ref |= self->GetPoisonObjectCookie() << kCookieShift;
+  }
+  return ref;
+}
+
+template<class MirrorType, bool kPoison>
+inline std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr) {
+  // May be used for dumping bad pointers, do not use the checked version.
+  return os << ptr.DecodeUnchecked();
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_OBJ_PTR_INL_H_
diff --git a/runtime/mirror/obj_ptr.h b/runtime/obj_ptr.h
similarity index 72%
rename from runtime/mirror/obj_ptr.h
rename to runtime/obj_ptr.h
index 10378e8..d5ac33d 100644
--- a/runtime/mirror/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -14,23 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_MIRROR_OBJ_PTR_H_
-#define ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#ifndef ART_RUNTIME_OBJ_PTR_H_
+#define ART_RUNTIME_OBJ_PTR_H_
+
+#include <ostream>
 
 #include "base/mutex.h"  // For Locks::mutator_lock_.
 #include "globals.h"
 #include "mirror/object_reference.h"
-#include "utils.h"
 
 namespace art {
-namespace mirror {
-
-class Object;
 
 // Value type representing a pointer to a mirror::Object of type MirrorType
 // Pass kPoison as a template boolean for testing in non-debug builds.
-// Note that the functions are not 100% thread safe and may have spurious positive check passes in
-// these cases.
+// Since the cookie is thread based, it is not safe to share an ObjPtr between threads.
 template<class MirrorType, bool kPoison = kIsDebugBuild>
 class ObjPtr {
   static constexpr size_t kCookieShift =
@@ -44,14 +41,19 @@
  public:
   ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
 
-  ALWAYS_INLINE explicit ObjPtr(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
-      : reference_(Encode(ptr)) {}
+  ALWAYS_INLINE ObjPtr(std::nullptr_t) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
 
-  ALWAYS_INLINE explicit ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_)
-      = default;
+  template <typename Type>
+  ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
+      : reference_(Encode(static_cast<MirrorType*>(ptr))) {}
 
+  template <typename Type>
+  ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_)
+      : reference_(Encode(static_cast<MirrorType*>(other.Decode()))) {}
+
+  template <typename Type>
   ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
-    reference_ = other.reference_;
+    reference_ = Encode(static_cast<MirrorType*>(other.Decode()));
     return *this;
   }
 
@@ -65,10 +67,6 @@
   }
 
   ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    return Get();
-  }
-
-  ALWAYS_INLINE MirrorType* Get() const REQUIRES_SHARED(Locks::mutator_lock_) {
     return Decode();
   }
 
@@ -76,19 +74,15 @@
     return reference_ == 0;
   }
 
-  ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (!kPoison || IsNull()) {
-      return true;
-    }
-    return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+  // Decode makes sure that the object pointer is valid.
+  ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    AssertValid();
+    return DecodeUnchecked();
   }
 
-  ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (kPoison) {
-      CHECK(IsValid()) << "Stale object pointer, expected cookie "
-          << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
-    }
-  }
+  ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+  ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
     return Decode() == ptr.Decode();
@@ -114,6 +108,16 @@
     return !IsNull();
   }
 
+  // Decode unchecked does not check that object pointer is valid. Do not use if you can avoid it.
+  ALWAYS_INLINE MirrorType* DecodeUnchecked() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (kPoison) {
+      return reinterpret_cast<MirrorType*>(
+          static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
+    } else {
+      return reinterpret_cast<MirrorType*>(reference_);
+    }
+  }
+
  private:
   // Trim off high bits of thread local cookie.
   ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) {
@@ -124,36 +128,20 @@
     return reference_ >> kCookieShift;
   }
 
-  ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
-    uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
-    if (kPoison && ref != 0) {
-      DCHECK_LE(ref, 0xFFFFFFFFU);
-      ref >>= kObjectAlignmentShift;
-      // Put cookie in high bits.
-      Thread* self = Thread::Current();
-      DCHECK(self != nullptr);
-      ref |= self->GetPoisonObjectCookie() << kCookieShift;
-    }
-    return ref;
-  }
-
-  // Decode makes sure that the object pointer is valid.
-  ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    AssertValid();
-    if (kPoison) {
-      return reinterpret_cast<MirrorType*>(
-          static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
-    } else {
-      return reinterpret_cast<MirrorType*>(reference_);
-    }
-  }
-
+  ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_);
   // The encoded reference and cookie.
   uintptr_t reference_;
 };
 
+template<class MirrorType, bool kPoison = kIsDebugBuild>
+static inline ObjPtr<MirrorType, kPoison> MakeObjPtr(MirrorType* ptr) {
+  return ObjPtr<MirrorType, kPoison>(ptr);
+}
 
-}  // namespace mirror
+template<class MirrorType, bool kPoison>
+ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
 }  // namespace art
 
-#endif  // ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#endif  // ART_RUNTIME_OBJ_PTR_H_
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 4a62ecd..d46d78c 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -43,7 +43,7 @@
 #include "thread_list.h"
 #include "runtime.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "mirror/class_loader.h"
 #include "verify_object-inl.h"
@@ -52,7 +52,7 @@
 #include "../../libcore/ojluni/src/main/native/jvm.h"  // TODO(narayan): fix it
 #include "jni_internal.h"
 #include "mirror/string-inl.h"
-#include "native/scoped_fast_native_object_access.h"
+#include "native/scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include <sys/time.h>
 #include <sys/socket.h>
@@ -286,9 +286,8 @@
 
 JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
   art::ScopedFastNativeObjectAccess soa(env);
-  art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr);
-  art::mirror::String* result = s->Intern();
-  return soa.AddLocalReference<jstring>(result);
+  art::ObjPtr<art::mirror::String> s = soa.Decode<art::mirror::String>(jstr);
+  return soa.AddLocalReference<jstring>(s->Intern());
 }
 
 JNIEXPORT jlong JVM_FreeMemory(void) {
@@ -364,8 +363,8 @@
 JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass ATTRIBUTE_UNUSED,
                          jobject java_lock, jlong millis) {
   art::ScopedFastNativeObjectAccess soa(env);
-  art::mirror::Object* lock = soa.Decode<art::mirror::Object*>(java_lock);
-  art::Monitor::Wait(art::Thread::Current(), lock, millis, 0, true, art::kSleeping);
+  art::ObjPtr<art::mirror::Object> lock = soa.Decode<art::mirror::Object>(java_lock);
+  art::Monitor::Wait(art::Thread::Current(), lock.Decode(), millis, 0, true, art::kSleeping);
 }
 
 JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) {
@@ -395,19 +394,19 @@
 
 JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject jobj) {
   art::ScopedObjectAccess soa(env);
-  art::mirror::Object* object = soa.Decode<art::mirror::Object*>(jobj);
-  if (object == NULL) {
+  art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobj);
+  if (object == nullptr) {
     art::ThrowNullPointerException("object == null");
     return JNI_FALSE;
   }
-  return soa.Self()->HoldsLock(object);
+  return soa.Self()->HoldsLock(object.Decode());
 }
 
 JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) {
   ScopedUtfChars name(env, java_name);
   {
     art::ScopedObjectAccess soa(env);
-    if (soa.Decode<art::mirror::Object*>(jthread) == soa.Self()->GetPeer()) {
+    if (soa.Decode<art::mirror::Object>(jthread) == soa.Self()->GetPeer()) {
       soa.Self()->SetThreadName(name.c_str());
       return;
     }
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index b5622b5..ac348e7 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -43,7 +43,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader-inl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "transform.h"
 #include "utf.h"
@@ -259,7 +259,7 @@
   JNIEnv* jni_env = *jni_env_ptr;
   art::ScopedObjectAccess soa(jni_env);
   art::StackHandleScope<3> hs(art::Thread::Current());
-  art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class*>(klass)));
+  art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
   *loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
   *name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
   // TODO is this always null?
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index e3f92c7..43b0b3d 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -23,7 +23,7 @@
 #include "common_compiler_test.h"
 #include "mirror/field-inl.h"
 #include "mirror/method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -108,7 +108,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> I(hs.NewHandle(
       class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -142,7 +142,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<9> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> I(hs.NewHandle(
       class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -200,7 +200,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<7> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> proxyClass0;
   Handle<mirror::Class> proxyClass1;
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index f04d41d..0be79ef 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -192,6 +192,13 @@
       } else {
         StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
       }
+    } else if (ref->IsReferenceInstance()) {
+      mirror::Object* referent = ref->AsReference()->GetReferent();
+      if (referent == nullptr) {
+        extras = " (referent is null)";
+      } else {
+        extras = StringPrintf(" (referent is a %s)", PrettyTypeOf(referent).c_str());
+      }
     }
     os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
   }
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index fae8e72..489db9a 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -16,18 +16,55 @@
 
 #include "reference_table.h"
 
+#include "class_linker.h"
 #include "common_runtime_test.h"
+#include "handle_scope-inl.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
 #include "mirror/string.h"
 #include "primitive.h"
-#include "scoped_thread_state_change.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
 
 class ReferenceTableTest : public CommonRuntimeTest {};
 
+static mirror::Object* CreateWeakReference(mirror::Object* referent)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  Thread* self = Thread::Current();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  StackHandleScope<3> scope(self);
+  Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent));
+
+  Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>(
+      class_linker->FindClass(self,
+                              "Ljava/lang/ref/WeakReference;",
+                              ScopedNullHandle<mirror::ClassLoader>())));
+  CHECK(h_ref_class.Get() != nullptr);
+  CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true));
+
+  Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>(
+      h_ref_class->AllocObject(self)));
+  CHECK(h_ref_instance.Get() != nullptr);
+
+  ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod(
+      "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
+  CHECK(constructor != nullptr);
+
+  uint32_t args[2];
+  args[0] = PointerToLowMemUInt32(h_ref_instance.Get());
+  args[1] = PointerToLowMemUInt32(h_referent.Get());
+  JValue result;
+  constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty());
+  CHECK(!self->IsExceptionPending());
+
+  return h_ref_instance.Get();
+}
+
 TEST_F(ReferenceTableTest, Basics) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello");
@@ -104,6 +141,29 @@
                 std::string::npos) << oss.str();
     }
   }
+
+  // Add a reference and check that the type of the referent is dumped.
+  {
+    mirror::Object* empty_reference = CreateWeakReference(nullptr);
+    ASSERT_TRUE(empty_reference->IsReferenceInstance());
+    rt.Add(empty_reference);
+    std::ostringstream oss;
+    rt.Dump(oss);
+    EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos)
+        << oss.str();
+  }
+
+  {
+    mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A");
+    mirror::Object* non_empty_reference = CreateWeakReference(string_referent);
+    ASSERT_TRUE(non_empty_reference->IsReferenceInstance());
+    rt.Add(non_empty_reference);
+    std::ostringstream oss;
+    rt.Dump(oss);
+    EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"),
+              std::string::npos)
+        << oss.str();
+  }
 }
 
 }  // namespace art
diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h
index f54d4ca..d7db8a4 100644
--- a/runtime/reflection-inl.h
+++ b/runtime/reflection-inl.h
@@ -23,14 +23,17 @@
 #include "common_throws.h"
 #include "jvalue.h"
 #include "mirror/object-inl.h"
+#include "obj_ptr-inl.h"
 #include "primitive.h"
 #include "utils.h"
 
 namespace art {
 
 inline bool ConvertPrimitiveValue(bool unbox_for_result,
-                                  Primitive::Type srcType, Primitive::Type dstType,
-                                  const JValue& src, JValue* dst) {
+                                  Primitive::Type srcType,
+                                  Primitive::Type dstType,
+                                  const JValue& src,
+                                  JValue* dst) {
   DCHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
   if (LIKELY(srcType == dstType)) {
     dst->SetJ(src.GetJ());
@@ -100,11 +103,11 @@
   return false;
 }
 
-inline bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
+inline bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
   if (UNLIKELY(o == nullptr)) {
     ThrowNullPointerException("null receiver");
     return false;
-  } else if (UNLIKELY(!o->InstanceOf(c))) {
+  } else if (UNLIKELY(!o->InstanceOf(c.Decode()))) {
     InvalidReceiverError(o, c);
     return false;
   }
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 30b10d8..b663b4c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -28,7 +28,7 @@
 #include "mirror/executable.h"
 #include "mirror/object_array-inl.h"
 #include "nth_caller_visitor.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_reference.h"
 #include "well_known_classes.h"
 
@@ -72,8 +72,8 @@
     num_bytes_ += 4;
   }
 
-  void Append(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
-    Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue());
+  void Append(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+    Append(StackReference<mirror::Object>::FromMirrorPtr(obj.Decode()).AsVRegValue());
   }
 
   void AppendWide(uint64_t value) {
@@ -95,7 +95,8 @@
   }
 
   void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
-                                mirror::Object* receiver, va_list ap)
+                                ObjPtr<mirror::Object> receiver,
+                                va_list ap)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Set receiver if non-null (method is not static)
     if (receiver != nullptr) {
@@ -114,7 +115,7 @@
           AppendFloat(va_arg(ap, jdouble));
           break;
         case 'L':
-          Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+          Append(soa.Decode<mirror::Object>(va_arg(ap, jobject)));
           break;
         case 'D':
           AppendDouble(va_arg(ap, jdouble));
@@ -131,7 +132,7 @@
   }
 
   void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                mirror::Object* receiver, jvalue* args)
+                                ObjPtr<mirror::Object> receiver, jvalue* args)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Set receiver if non-null (method is not static)
     if (receiver != nullptr) {
@@ -156,7 +157,7 @@
           Append(args[args_offset].i);
           break;
         case 'L':
-          Append(soa.Decode<mirror::Object*>(args[args_offset].l));
+          Append(soa.Decode<mirror::Object>(args[args_offset].l));
           break;
         case 'D':
         case 'J':
@@ -212,8 +213,9 @@
                      PrettyDescriptor(found_descriptor).c_str()).c_str());
   }
 
-  bool BuildArgArrayFromObjectArray(mirror::Object* receiver,
-                                    mirror::ObjectArray<mirror::Object>* args, ArtMethod* m)
+  bool BuildArgArrayFromObjectArray(ObjPtr<mirror::Object> receiver,
+                                    ObjPtr<mirror::ObjectArray<mirror::Object>> args,
+                                    ArtMethod* m)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     const DexFile::TypeList* classes = m->GetParameterTypeList();
     // Set receiver if non-null (method is not static)
@@ -221,13 +223,13 @@
       Append(receiver);
     }
     for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
-      mirror::Object* arg = args->Get(args_offset);
+      ObjPtr<mirror::Object> arg(args->Get(args_offset));
       if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
         PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-        mirror::Class* dst_class =
+        ObjPtr<mirror::Class> dst_class(
             m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_,
                                      true /* resolve */,
-                                     pointer_size);
+                                     pointer_size));
         if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
           ThrowIllegalArgumentException(
               StringPrintf("method %s argument %zd has type %s, got %s",
@@ -240,15 +242,15 @@
       }
 
 #define DO_FIRST_ARG(match_descriptor, get_fn, append) { \
-          if (LIKELY(arg != nullptr && arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
+          if (LIKELY(arg != nullptr && arg->GetClass()->DescriptorEquals(match_descriptor))) { \
             ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
-            append(primitive_field-> get_fn(arg));
+            append(primitive_field-> get_fn(arg.Decode()));
 
 #define DO_ARG(match_descriptor, get_fn, append) \
           } else if (LIKELY(arg != nullptr && \
                             arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
             ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
-            append(primitive_field-> get_fn(arg));
+            append(primitive_field-> get_fn(arg.Decode()));
 
 #define DO_FAIL(expected) \
           } else { \
@@ -362,9 +364,9 @@
   PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
   for (uint32_t i = 0; i < num_params; i++) {
     uint16_t type_idx = params->GetTypeItem(i).type_idx_;
-    mirror::Class* param_type = m->GetClassFromTypeIndex(type_idx,
-                                                         true /* resolve*/,
-                                                         pointer_size);
+    ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
+                                                              true /* resolve*/,
+                                                              pointer_size));
     if (param_type == nullptr) {
       CHECK(self->IsExceptionPending());
       LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
@@ -376,7 +378,7 @@
       // TODO: There is a compaction bug here since GetClassFromTypeIdx can cause thread suspension,
       // this is a hard to fix problem since the args can contain Object*, we need to save and
       // restore them by using a visitor similar to the ones used in the trampoline entrypoints.
-      mirror::Object* argument =
+      ObjPtr<mirror::Object> argument =
           (reinterpret_cast<StackReference<mirror::Object>*>(&args[i + offset]))->AsMirrorPtr();
       if (argument != nullptr && !argument->InstanceOf(param_type)) {
         LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
@@ -423,7 +425,7 @@
   }
 }
 
-static ArtMethod* FindVirtualMethod(mirror::Object* receiver, ArtMethod* method)
+static ArtMethod* FindVirtualMethod(ObjPtr<mirror::Object> receiver, ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method, kRuntimePointerSize);
 }
@@ -457,7 +459,7 @@
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
   }
-  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
   uint32_t shorty_len = 0;
   const char* shorty =
       method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -488,7 +490,7 @@
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
   }
-  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
   uint32_t shorty_len = 0;
   const char* shorty =
       method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -513,7 +515,7 @@
     return JValue();
   }
 
-  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
@@ -545,7 +547,7 @@
     return JValue();
   }
 
-  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
@@ -578,21 +580,20 @@
     return nullptr;
   }
 
-  auto* executable = soa.Decode<mirror::Executable*>(javaMethod);
+  ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(javaMethod);
   const bool accessible = executable->IsAccessible();
   ArtMethod* m = executable->GetArtMethod();
 
-  mirror::Class* declaring_class = m->GetDeclaringClass();
+  ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
   if (UNLIKELY(!declaring_class->IsInitialized())) {
     StackHandleScope<1> hs(soa.Self());
-    Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
+    HandleWrapperObjPtr<mirror::Class> h_class(hs.NewHandleWrapper(&declaring_class));
     if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_class, true, true)) {
       return nullptr;
     }
-    declaring_class = h_class.Get();
   }
 
-  mirror::Object* receiver = nullptr;
+  ObjPtr<mirror::Object> receiver;
   if (!m->IsStatic()) {
     // Replace calls to String.<init> with equivalent StringFactory call.
     if (declaring_class->IsStringClass() && m->IsConstructor()) {
@@ -600,7 +601,7 @@
       CHECK(javaReceiver == nullptr);
     } else {
       // Check that the receiver is non-null and an instance of the field's declaring class.
-      receiver = soa.Decode<mirror::Object*>(javaReceiver);
+      receiver = soa.Decode<mirror::Object>(javaReceiver);
       if (!VerifyObjectIsClass(receiver, declaring_class)) {
         return nullptr;
       }
@@ -611,7 +612,8 @@
   }
 
   // Get our arrays of arguments and their types, and check they're the same size.
-  auto* objects = soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
+  ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
+      soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
   auto* np_method = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
   const DexFile::TypeList* classes = np_method->GetParameterTypeList();
   uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
@@ -623,7 +625,7 @@
   }
 
   // If method is not set to be accessible, verify it can be accessed by the caller.
-  mirror::Class* calling_class = nullptr;
+  ObjPtr<mirror::Class> calling_class;
   if (!accessible && !VerifyAccess(soa.Self(),
                                    receiver,
                                    declaring_class,
@@ -674,12 +676,13 @@
   }
 
   // Box if necessary and return.
-  return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
+  return soa.AddLocalReference<jobject>(
+      BoxPrimitive(Primitive::GetType(shorty[0]), result).Decode());
 }
 
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
   if (src_class == Primitive::kPrimNot) {
-    return value.GetL();
+    return MakeObjPtr(value.GetL());
   }
   if (src_class == Primitive::kPrimVoid) {
     // There's no such thing as a void field, and void methods invoked via reflection return null.
@@ -750,8 +753,9 @@
   return "result";
 }
 
-static bool UnboxPrimitive(mirror::Object* o,
-                           mirror::Class* dst_class, ArtField* f,
+static bool UnboxPrimitive(ObjPtr<mirror::Object> o,
+                           ObjPtr<mirror::Class> dst_class,
+                           ArtField* f,
                            JValue* unboxed_value)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   bool unbox_for_result = (f == nullptr);
@@ -769,7 +773,7 @@
       }
       return false;
     }
-    unboxed_value->SetL(o);
+    unboxed_value->SetL(o.Decode());
     return true;
   }
   if (UNLIKELY(dst_class->GetPrimitiveType() == Primitive::kPrimVoid)) {
@@ -791,34 +795,34 @@
   }
 
   JValue boxed_value;
-  mirror::Class* klass = o->GetClass();
-  mirror::Class* src_class = nullptr;
+  ObjPtr<mirror::Class> klass = o->GetClass();
+  ObjPtr<mirror::Class> src_class = nullptr;
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0);
   if (klass->DescriptorEquals("Ljava/lang/Boolean;")) {
     src_class = class_linker->FindPrimitiveClass('Z');
-    boxed_value.SetZ(primitive_field->GetBoolean(o));
+    boxed_value.SetZ(primitive_field->GetBoolean(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Byte;")) {
     src_class = class_linker->FindPrimitiveClass('B');
-    boxed_value.SetB(primitive_field->GetByte(o));
+    boxed_value.SetB(primitive_field->GetByte(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Character;")) {
     src_class = class_linker->FindPrimitiveClass('C');
-    boxed_value.SetC(primitive_field->GetChar(o));
+    boxed_value.SetC(primitive_field->GetChar(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Float;")) {
     src_class = class_linker->FindPrimitiveClass('F');
-    boxed_value.SetF(primitive_field->GetFloat(o));
+    boxed_value.SetF(primitive_field->GetFloat(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Double;")) {
     src_class = class_linker->FindPrimitiveClass('D');
-    boxed_value.SetD(primitive_field->GetDouble(o));
+    boxed_value.SetD(primitive_field->GetDouble(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Integer;")) {
     src_class = class_linker->FindPrimitiveClass('I');
-    boxed_value.SetI(primitive_field->GetInt(o));
+    boxed_value.SetI(primitive_field->GetInt(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Long;")) {
     src_class = class_linker->FindPrimitiveClass('J');
-    boxed_value.SetJ(primitive_field->GetLong(o));
+    boxed_value.SetJ(primitive_field->GetLong(o.Decode()));
   } else if (klass->DescriptorEquals("Ljava/lang/Short;")) {
     src_class = class_linker->FindPrimitiveClass('S');
-    boxed_value.SetS(primitive_field->GetShort(o));
+    boxed_value.SetS(primitive_field->GetShort(o.Decode()));
   } else {
     std::string temp;
     ThrowIllegalArgumentException(
@@ -833,28 +837,36 @@
                                boxed_value, unboxed_value);
 }
 
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+                            ObjPtr<mirror::Class> dst_class,
+                            ArtField* f,
                             JValue* unboxed_value) {
   DCHECK(f != nullptr);
   return UnboxPrimitive(o, dst_class, f, unboxed_value);
 }
 
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value) {
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+                             ObjPtr<mirror::Class> dst_class,
+                             JValue* unboxed_value) {
   return UnboxPrimitive(o, dst_class, nullptr, unboxed_value);
 }
 
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames) {
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames) {
   NthCallerVisitor visitor(self, num_frames);
   visitor.WalkStack();
   return visitor.caller != nullptr ? visitor.caller->GetDeclaringClass() : nullptr;
 }
 
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class** calling_class, size_t num_frames) {
+bool VerifyAccess(Thread* self,
+                  ObjPtr<mirror::Object> obj,
+                  ObjPtr<mirror::Class> declaring_class,
+                  uint32_t access_flags,
+                  ObjPtr<mirror::Class>* calling_class,
+                  size_t num_frames) {
   if ((access_flags & kAccPublic) != 0) {
     return true;
   }
-  auto* klass = GetCallingClass(self, num_frames);
+  ObjPtr<mirror::Class> klass = GetCallingClass(self, num_frames);
   if (UNLIKELY(klass == nullptr)) {
     // The caller is an attached native thread.
     return false;
@@ -863,10 +875,10 @@
   return VerifyAccess(obj, declaring_class, access_flags, klass);
 }
 
-bool VerifyAccess(mirror::Object* obj,
-                  mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+                  ObjPtr<mirror::Class> declaring_class,
                   uint32_t access_flags,
-                  mirror::Class* calling_class) {
+                  ObjPtr<mirror::Class> calling_class) {
   if (calling_class == declaring_class) {
     return true;
   }
@@ -876,16 +888,16 @@
   }
   if ((access_flags & kAccProtected) != 0) {
     if (obj != nullptr && !obj->InstanceOf(calling_class) &&
-        !declaring_class->IsInSamePackage(calling_class)) {
+        !declaring_class->IsInSamePackage(calling_class.Decode())) {
       return false;
-    } else if (declaring_class->IsAssignableFrom(calling_class)) {
+    } else if (declaring_class->IsAssignableFrom(calling_class.Decode())) {
       return true;
     }
   }
-  return declaring_class->IsInSamePackage(calling_class);
+  return declaring_class->IsInSamePackage(calling_class.Decode());
 }
 
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c) {
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
   std::string expected_class_name(PrettyDescriptor(c));
   std::string actual_class_name(PrettyTypeOf(o));
   ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s",
@@ -895,18 +907,18 @@
 
 // This only works if there's one reference which points to the object in obj.
 // Will need to be fixed if there's cases where it's not.
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result) {
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) {
   IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
   IndirectRefKind kind = GetIndirectRefKind(ref);
   if (kind == kLocal) {
-    self->GetJniEnv()->locals.Update(obj, result);
+    self->GetJniEnv()->locals.Update(obj, result.Decode());
   } else if (kind == kHandleScopeOrInvalid) {
     LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid";
   } else if (kind == kGlobal) {
-    self->GetJniEnv()->vm->UpdateGlobal(self, ref, result);
+    self->GetJniEnv()->vm->UpdateGlobal(self, ref, result.Decode());
   } else {
     DCHECK_EQ(kind, kWeakGlobal);
-    self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result);
+    self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result.Decode());
   }
 }
 
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 208b533..6e5ef71 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -19,6 +19,7 @@
 
 #include "base/mutex.h"
 #include "jni.h"
+#include "obj_ptr.h"
 #include "primitive.h"
 
 namespace art {
@@ -32,62 +33,85 @@
 class ScopedObjectAccessAlreadyRunnable;
 class ShadowFrame;
 
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value)
     REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+                            ObjPtr<mirror::Class> dst_class,
+                            ArtField* f,
                             JValue* unboxed_value)
     REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value)
+
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+                             ObjPtr<mirror::Class> dst_class,
+                             JValue* unboxed_value)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 ALWAYS_INLINE bool ConvertPrimitiveValue(bool unbox_for_result,
-                                         Primitive::Type src_class, Primitive::Type dst_class,
-                                         const JValue& src, JValue* dst)
+                                         Primitive::Type src_class,
+                                         Primitive::Type dst_class,
+                                         const JValue& src,
+                                         JValue* dst)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         jmethodID mid,
                          va_list args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         jmethodID mid,
                          jvalue* args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           jobject obj, jmethodID mid, jvalue* args)
+                                           jobject obj,
+                                           jmethodID mid,
+                                           jvalue* args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           jobject obj, jmethodID mid, va_list args)
+                                           jobject obj,
+                                           jmethodID mid,
+                                           va_list args)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // num_frames is number of frames we look up for access check.
-jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
-                     jobject args, size_t num_frames = 1)
+jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa,
+                     jobject method,
+                     jobject receiver,
+                     jobject args,
+                     size_t num_frames = 1)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c)
+ALWAYS_INLINE bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class** calling_class, size_t num_frames)
+bool VerifyAccess(Thread* self,
+                  ObjPtr<mirror::Object> obj,
+                  ObjPtr<mirror::Class> declaring_class,
+                  uint32_t access_flags,
+                  ObjPtr<mirror::Class>* calling_class,
+                  size_t num_frames)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // This version takes a known calling class.
-bool VerifyAccess(mirror::Object* obj,
-                  mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+                  ObjPtr<mirror::Class> declaring_class,
                   uint32_t access_flags,
-                  mirror::Class* calling_class)
+                  ObjPtr<mirror::Class> calling_class)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Get the calling class by using a stack visitor, may return null for unattached native threads.
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames)
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c)
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result)
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 }  // namespace art
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 4876ff0..189ed03 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -23,7 +23,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "common_compiler_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -93,16 +93,12 @@
     StackHandleScope<2> hs(self);
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(
-            ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader)));
-    if (is_static) {
-      MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
-                     class_name);
-    } else {
+            ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader>(jclass_loader)));
+    if (!is_static) {
       MakeExecutable(nullptr, "java.lang.Class");
       MakeExecutable(nullptr, "java.lang.Object");
-      MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
-                     class_name);
     }
+    MakeExecutable(class_loader.Get(), class_name);
 
     mirror::Class* c = class_linker_->FindClass(self, DotToDescriptor(class_name).c_str(),
                                                 class_loader);
@@ -512,7 +508,7 @@
   jobject jclass_loader = LoadDex("Main");
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V");
 
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5bb38f5..df0dca0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -88,6 +88,8 @@
 #include "mirror/class_loader.h"
 #include "mirror/field.h"
 #include "mirror/method.h"
+#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
 #include "mirror/stack_trace_element.h"
 #include "mirror/throwable.h"
 #include "monitor.h"
@@ -131,7 +133,7 @@
 #include "reflection.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "sigchain.h"
 #include "signal_catcher.h"
 #include "signal_set.h"
@@ -528,7 +530,7 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::Class> class_loader_class(
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader)));
   CHECK(cl->EnsureInitialized(soa.Self(), class_loader_class, true, true));
 
   ArtMethod* getSystemClassLoader = class_loader_class->FindDirectMethod(
@@ -543,7 +545,7 @@
   soa.Self()->SetClassLoaderOverride(system_class_loader.get());
 
   Handle<mirror::Class> thread_class(
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread)));
   CHECK(cl->EnsureInitialized(soa.Self(), thread_class, true, true));
 
   ArtField* contextClassLoader =
@@ -551,8 +553,9 @@
   CHECK(contextClassLoader != nullptr);
 
   // We can't run in a transaction yet.
-  contextClassLoader->SetObject<false>(soa.Self()->GetPeer(),
-                                       soa.Decode<mirror::ClassLoader*>(system_class_loader.get()));
+  contextClassLoader->SetObject<false>(
+      soa.Self()->GetPeer(),
+      soa.Decode<mirror::ClassLoader>(system_class_loader.get()).Decode());
 
   return env->NewGlobalRef(system_class_loader.get());
 }
@@ -1547,6 +1550,8 @@
   mirror::String::VisitRoots(visitor);
   mirror::Throwable::VisitRoots(visitor);
   mirror::Field::VisitRoots(visitor);
+  mirror::MethodType::VisitRoots(visitor);
+  mirror::MethodHandleImpl::VisitRoots(visitor);
   // Visit all the primitive array types classes.
   mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor);   // BooleanArray
   mirror::PrimitiveArray<int8_t>::VisitRoots(visitor);    // ByteArray
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
new file mode 100644
index 0000000..cf020d0
--- /dev/null
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+#define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+
+#include "scoped_thread_state_change.h"
+
+#include "jni_env_ext-inl.h"
+#include "obj_ptr-inl.h"
+#include "thread-inl.h"
+
+namespace art {
+
+inline ScopedThreadStateChange::ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+    : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
+  if (UNLIKELY(self_ == nullptr)) {
+    // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
+    old_thread_state_ = kTerminated;
+    Runtime* runtime = Runtime::Current();
+    CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
+  } else {
+    DCHECK_EQ(self, Thread::Current());
+    // Read state without locks, ok as state is effectively thread local and we're not interested
+    // in the suspend count (this will be handled in the runnable transitions).
+    old_thread_state_ = self->GetState();
+    if (old_thread_state_ != new_thread_state) {
+      if (new_thread_state == kRunnable) {
+        self_->TransitionFromSuspendedToRunnable();
+      } else if (old_thread_state_ == kRunnable) {
+        self_->TransitionFromRunnableToSuspended(new_thread_state);
+      } else {
+        // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+        self_->SetState(new_thread_state);
+      }
+    }
+  }
+}
+
+inline ScopedThreadStateChange::~ScopedThreadStateChange() {
+  if (UNLIKELY(self_ == nullptr)) {
+    if (!expected_has_no_thread_) {
+      Runtime* runtime = Runtime::Current();
+      bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
+      CHECK(shutting_down);
+    }
+  } else {
+    if (old_thread_state_ != thread_state_) {
+      if (old_thread_state_ == kRunnable) {
+        self_->TransitionFromSuspendedToRunnable();
+      } else if (thread_state_ == kRunnable) {
+        self_->TransitionFromRunnableToSuspended(old_thread_state_);
+      } else {
+        // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+        self_->SetState(old_thread_state_);
+      }
+    }
+  }
+}
+
+template<typename T>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(mirror::Object* obj) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
+  return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
+}
+
+template<typename T, typename MirrorType, bool kPoison>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(
+    ObjPtr<MirrorType, kPoison> obj) const {
+  return AddLocalReference<T>(obj.Decode());
+}
+
+template<typename T, bool kPoison>
+inline ObjPtr<T, kPoison> ScopedObjectAccessAlreadyRunnable::Decode(jobject obj) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return down_cast<T*>(Self()->DecodeJObject(obj));
+}
+
+inline ArtField* ScopedObjectAccessAlreadyRunnable::DecodeField(jfieldID fid) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<ArtField*>(fid);
+}
+
+inline jfieldID ScopedObjectAccessAlreadyRunnable::EncodeField(ArtField* field) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<jfieldID>(field);
+}
+
+inline ArtMethod* ScopedObjectAccessAlreadyRunnable::DecodeMethod(jmethodID mid) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<ArtMethod*>(mid);
+}
+
+inline jmethodID ScopedObjectAccessAlreadyRunnable::EncodeMethod(ArtMethod* method) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<jmethodID>(method);
+}
+
+inline bool ScopedObjectAccessAlreadyRunnable::IsRunnable() const {
+  return self_->GetState() == kRunnable;
+}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+    : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(Thread* self)
+    : self_(self),
+      env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
+      vm_(env_ != nullptr ? env_->vm : nullptr) {}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(JNIEnv* env)
+    : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
+  Self()->VerifyStack();
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(Thread* self)
+    : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
+  Self()->VerifyStack();
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedThreadSuspension::ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+    : self_(self), suspended_state_(suspended_state) {
+  DCHECK(self_ != nullptr);
+  self_->TransitionFromRunnableToSuspended(suspended_state);
+}
+
+inline ScopedThreadSuspension::~ScopedThreadSuspension() {
+  DCHECK_EQ(self_->GetState(), suspended_state_);
+  self_->TransitionFromSuspendedToRunnable();
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 8a1aca5..175bec5 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -17,85 +17,43 @@
 #ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
 #define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
 
-#include "base/casts.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext-inl.h"
 #include "art_field.h"
-#include "read_barrier.h"
-#include "thread-inl.h"
+#include "base/casts.h"
+#include "base/value_object.h"
+#include "java_vm_ext.h"
+#include "thread_state.h"
 #include "verify_object.h"
 
 namespace art {
 
+struct JNIEnvExt;
+template<class MirrorType, bool kPoison> class ObjPtr;
+
 // Scoped change into and out of a particular state. Handles Runnable transitions that require
 // more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and
 // ScopedObjectAccess are used to handle the change into Runnable to Get direct access to objects,
 // the unchecked variant doesn't aid annotalysis.
 class ScopedThreadStateChange : public ValueObject {
  public:
-  ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
-    if (UNLIKELY(self_ == nullptr)) {
-      // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
-      old_thread_state_ = kTerminated;
-      Runtime* runtime = Runtime::Current();
-      CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
-    } else {
-      DCHECK_EQ(self, Thread::Current());
-      // Read state without locks, ok as state is effectively thread local and we're not interested
-      // in the suspend count (this will be handled in the runnable transitions).
-      old_thread_state_ = self->GetState();
-      if (old_thread_state_ != new_thread_state) {
-        if (new_thread_state == kRunnable) {
-          self_->TransitionFromSuspendedToRunnable();
-        } else if (old_thread_state_ == kRunnable) {
-          self_->TransitionFromRunnableToSuspended(new_thread_state);
-        } else {
-          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
-          self_->SetState(new_thread_state);
-        }
-      }
-    }
-  }
+  ALWAYS_INLINE ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE {
-    if (UNLIKELY(self_ == nullptr)) {
-      if (!expected_has_no_thread_) {
-        Runtime* runtime = Runtime::Current();
-        bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
-        CHECK(shutting_down);
-      }
-    } else {
-      if (old_thread_state_ != thread_state_) {
-        if (old_thread_state_ == kRunnable) {
-          self_->TransitionFromSuspendedToRunnable();
-        } else if (thread_state_ == kRunnable) {
-          self_->TransitionFromRunnableToSuspended(old_thread_state_);
-        } else {
-          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
-          self_->SetState(old_thread_state_);
-        }
-      }
-    }
-  }
+  ALWAYS_INLINE ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  Thread* Self() const {
+  ALWAYS_INLINE Thread* Self() const {
     return self_;
   }
 
  protected:
   // Constructor used by ScopedJniThreadState for an unattached thread that has access to the VM*.
-  ScopedThreadStateChange()
-      : self_(nullptr), thread_state_(kTerminated), old_thread_state_(kTerminated),
-        expected_has_no_thread_(true) {}
+  ScopedThreadStateChange() {}
 
-  Thread* const self_;
-  const ThreadState thread_state_;
+  Thread* const self_ = nullptr;
+  const ThreadState thread_state_ = kTerminated;
 
  private:
-  ThreadState old_thread_state_;
-  const bool expected_has_no_thread_;
+  ThreadState old_thread_state_ = kTerminated;
+  const bool expected_has_no_thread_ = true;
 
   friend class ScopedObjectAccessUnchecked;
   DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange);
@@ -129,62 +87,34 @@
    * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
    * it's best if we don't grab a mutex.
    */
+  template<typename T, typename MirrorType, bool kPoison = kIsDebugBuild>
+  T AddLocalReference(ObjPtr<MirrorType, kPoison> obj) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // TODO: Delete
   template<typename T>
-  T AddLocalReference(mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
-    return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
-  }
+  T AddLocalReference(mirror::Object* obj) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template<typename T>
-  T Decode(jobject obj) const
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return down_cast<T>(Self()->DecodeJObject(obj));
-  }
+  template<typename T, bool kPoison = kIsDebugBuild>
+  ObjPtr<T, kPoison> Decode(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtField* DecodeField(jfieldID fid) const
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<ArtField*>(fid);
-  }
+  ArtField* DecodeField(jfieldID fid) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<jfieldID>(field);
-  }
+  jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<ArtMethod*>(mid);
-  }
+  ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<jmethodID>(method);
-  }
+  jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool IsRunnable() const {
-    return self_->GetState() == kRunnable;
-  }
+  ALWAYS_INLINE bool IsRunnable() const;
 
  protected:
-  explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(self), env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
-        vm_(env_ != nullptr ? env_->vm : nullptr) {
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
   // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
   // change into Runnable or acquire a share on the mutator_lock_.
@@ -192,8 +122,7 @@
       : self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {}
 
   // Here purely to force inlining.
-  ~ScopedObjectAccessAlreadyRunnable() ALWAYS_INLINE {
-  }
+  ALWAYS_INLINE ~ScopedObjectAccessAlreadyRunnable() {}
 
   // Self thread, can be null.
   Thread* const self_;
@@ -219,19 +148,11 @@
 // the mutator_lock_ will be acquired on construction.
 class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable {
  public:
-  explicit ScopedObjectAccessUnchecked(JNIEnv* env)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
-    Self()->VerifyStack();
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(JNIEnv* env)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  explicit ScopedObjectAccessUnchecked(Thread* self)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
-    Self()->VerifyStack();
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(Thread* self)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
   // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
   // change into Runnable or acquire a share on the mutator_lock_.
@@ -249,28 +170,24 @@
 // Annotalysis helping variant of the above.
 class ScopedObjectAccess : public ScopedObjectAccessUnchecked {
  public:
-  explicit ScopedObjectAccess(JNIEnv* env)
+  ALWAYS_INLINE explicit ScopedObjectAccess(JNIEnv* env)
       REQUIRES(!Locks::thread_suspend_count_lock_)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessUnchecked(env) {
-  }
+      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+      : ScopedObjectAccessUnchecked(env) {}
 
-  explicit ScopedObjectAccess(Thread* self)
+  ALWAYS_INLINE explicit ScopedObjectAccess(Thread* self)
       REQUIRES(!Locks::thread_suspend_count_lock_)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessUnchecked(self) {
-  }
+      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+      : ScopedObjectAccessUnchecked(self) {}
 
-  ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-    // Base class will release share of lock. Invoked after this destructor.
-  }
+  // Base class will release share of lock. Invoked after this destructor.
+  ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {}
 
  private:
   // TODO: remove this constructor. It is used by check JNI's ScopedCheck to make it believe that
   //       routines operating with just a VM are sound, they are not, but when you have just a VM
   //       you cannot call the unsound routines.
-  explicit ScopedObjectAccess(JavaVM* vm)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+  explicit ScopedObjectAccess(JavaVM* vm) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
       : ScopedObjectAccessUnchecked(vm) {}
 
   friend class ScopedCheck;
@@ -280,19 +197,11 @@
 // Annotalysis helper for going to a suspended state from runnable.
 class ScopedThreadSuspension : public ValueObject {
  public:
-  explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+  ALWAYS_INLINE explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
       REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
-      UNLOCK_FUNCTION(Locks::mutator_lock_)
-      ALWAYS_INLINE
-      : self_(self), suspended_state_(suspended_state) {
-    DCHECK(self_ != nullptr);
-    self_->TransitionFromRunnableToSuspended(suspended_state);
-  }
+      UNLOCK_FUNCTION(Locks::mutator_lock_);
 
-  ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-    DCHECK_EQ(self_->GetState(), suspended_state_);
-    self_->TransitionFromSuspendedToRunnable();
-  }
+  ALWAYS_INLINE ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
 
  private:
   Thread* const self_;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 848c0e3..674459d 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -34,7 +34,7 @@
 #include "gc/heap.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "signal_set.h"
 #include "thread.h"
 #include "thread_list.h"
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 298a974..bb6eb79 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -59,6 +59,8 @@
   if (UNLIKELY(TestAllFlags())) {
     CheckSuspend();
   }
+  // Invalidate the current thread's object pointers (ObjPtr) to catch possible moving GC bugs due
+  // to missing handles.
   PoisonObjectPointers();
 }
 
@@ -173,6 +175,9 @@
 
 inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
   AssertThreadSuspensionIsAllowable();
+  if (kIsDebugBuild) {
+    PoisonObjectPointers();
+  }
   DCHECK_EQ(this, Thread::Current());
   // Change to non-runnable state, thereby appearing suspended to the system.
   TransitionToSuspendedAndRunCheckpoints(new_state);
@@ -303,6 +308,12 @@
   tlsPtr_.thread_local_alloc_stack_top = nullptr;
 }
 
+inline void Thread::PoisonObjectPointersIfDebug() {
+  if (kIsDebugBuild) {
+    Thread::Current()->PoisonObjectPointers();
+  }
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d0ea2d7..ec1bb3f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -59,12 +59,13 @@
 #include "native_stack_dump.h"
 #include "nth_caller_visitor.h"
 #include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
 #include "object_lock.h"
 #include "quick_exception_handler.h"
 #include "quick/quick_method_frame_info.h"
 #include "reflection.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "stack.h"
@@ -406,7 +407,7 @@
 
     // Copy peer into self, deleting global reference when done.
     CHECK(self->tlsPtr_.jpeer != nullptr);
-    self->tlsPtr_.opeer = soa.Decode<mirror::Object*>(self->tlsPtr_.jpeer);
+    self->tlsPtr_.opeer = soa.Decode<mirror::Object>(self->tlsPtr_.jpeer).Decode();
     self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
     self->tlsPtr_.jpeer = nullptr;
     self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
@@ -444,7 +445,7 @@
 
 Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa,
                                   jobject java_thread) {
-  return FromManagedThread(soa, soa.Decode<mirror::Object*>(java_thread));
+  return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread).Decode());
 }
 
 static size_t FixStackSize(size_t stack_size) {
@@ -563,7 +564,7 @@
 
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
     mirror::String* java_name = reinterpret_cast<mirror::String*>(f->GetObject(
-        soa.Decode<mirror::Object*>(java_peer)));
+        soa.Decode<mirror::Object>(java_peer).Decode()));
     std::string thread_name;
     if (java_name != nullptr) {
       thread_name = java_name->ToModifiedUtf8();
@@ -802,7 +803,7 @@
   }
   {
     ScopedObjectAccess soa(this);
-    tlsPtr_.opeer = soa.Decode<mirror::Object*>(peer.get());
+    tlsPtr_.opeer = soa.Decode<mirror::Object>(peer.get()).Decode();
   }
   env->CallNonvirtualVoidMethod(peer.get(),
                                 WellKnownClasses::java_lang_Thread,
@@ -844,9 +845,11 @@
   soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
       SetBoolean<kTransactionActive>(tlsPtr_.opeer, thread_is_daemon);
   soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
-      SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object*>(thread_group));
+      SetObject<kTransactionActive>(tlsPtr_.opeer,
+                                    soa.Decode<mirror::Object>(thread_group).Decode());
   soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
-      SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object*>(thread_name));
+      SetObject<kTransactionActive>(tlsPtr_.opeer,
+                                    soa.Decode<mirror::Object>(thread_name).Decode());
   soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
       SetInt<kTransactionActive>(tlsPtr_.opeer, thread_priority);
 }
@@ -2123,7 +2126,7 @@
     int* stack_depth) {
   // Decode the internal stack trace into the depth, method trace and PC trace.
   // Subtract one for the methods and PC trace.
-  int32_t depth = soa.Decode<mirror::Array*>(internal)->GetLength() - 1;
+  int32_t depth = soa.Decode<mirror::Array>(internal)->GetLength() - 1;
   DCHECK_GE(depth, 0);
 
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -2135,7 +2138,7 @@
     result = output_array;
     // ...adjusting the number of frames we'll write to not exceed the array length.
     const int32_t traces_length =
-        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->GetLength();
+        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->GetLength();
     depth = std::min(depth, traces_length);
   } else {
     // Create java_trace array and place in local reference table
@@ -2153,7 +2156,7 @@
 
   for (int32_t i = 0; i < depth; ++i) {
     mirror::ObjectArray<mirror::Object>* decoded_traces =
-        soa.Decode<mirror::Object*>(internal)->AsObjectArray<mirror::Object>();
+        soa.Decode<mirror::Object>(internal)->AsObjectArray<mirror::Object>();
     // Methods and dex PC trace is element 0.
     DCHECK(decoded_traces->Get(0)->IsIntArray() || decoded_traces->Get(0)->IsLongArray());
     mirror::PointerArray* const method_trace =
@@ -2205,7 +2208,7 @@
       return nullptr;
     }
     // We are called from native: use non-transactional mode.
-    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set<false>(i, obj);
+    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->Set<false>(i, obj);
   }
   return result;
 }
@@ -3044,11 +3047,10 @@
   interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result);
 }
 
-void Thread::SetException(mirror::Throwable* new_exception) {
+void Thread::SetException(ObjPtr<mirror::Throwable> new_exception) {
   CHECK(new_exception != nullptr);
   // TODO: DCHECK(!IsExceptionPending());
-  tlsPtr_.exception = new_exception;
-  // LOG(ERROR) << new_exception->Dump();
+  tlsPtr_.exception = new_exception.Decode();
 }
 
 }  // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index fb6bde6..f2c22d1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -366,7 +366,7 @@
   void AssertNoPendingException() const;
   void AssertNoPendingExceptionForNewException(const char* msg) const;
 
-  void SetException(mirror::Throwable* new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetException(ObjPtr<mirror::Throwable> new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
 
   void ClearException() REQUIRES_SHARED(Locks::mutator_lock_) {
     tlsPtr_.exception = nullptr;
@@ -475,6 +475,8 @@
     ++poison_object_cookie_;
   }
 
+  ALWAYS_INLINE static void PoisonObjectPointersIfDebug();
+
   ALWAYS_INLINE uintptr_t GetPoisonObjectCookie() const {
     return poison_object_cookie_;
   }
@@ -900,7 +902,9 @@
 
   // Returns the fake exception used to activate deoptimization.
   static mirror::Throwable* GetDeoptimizationException() {
-    return reinterpret_cast<mirror::Throwable*>(-1);
+    // Note that the mirror::Throwable must be aligned to kObjectAlignment or else it cannot be
+    // represented by ObjPtr.
+    return reinterpret_cast<mirror::Throwable*>(0x100);
   }
 
   // Currently deoptimization invokes verifier which can trigger class loading
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 17c6c2e..e2aca6a 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -36,7 +36,7 @@
 #include "lock_word.h"
 #include "monitor.h"
 #include "native_stack_dump.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "trace.h"
 #include "well_known_classes.h"
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 23591c2..f8467467 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -37,7 +37,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "thread.h"
 #include "thread_list.h"
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 82e529c..77c2b76 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -22,7 +22,7 @@
 #include "common_runtime_test.h"
 #include "dex_file.h"
 #include "mirror/array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -36,7 +36,7 @@
     jobject jclass_loader = LoadDex("Transaction");
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     ASSERT_TRUE(class_loader.Get() != nullptr);
 
     // Load and initialize java.lang.ExceptionInInitializerError and the exception class used
@@ -173,7 +173,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -271,7 +271,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<5> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -373,7 +373,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -490,7 +490,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -539,7 +539,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -563,7 +563,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index ea4d8b5..ec38b41 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -19,7 +19,7 @@
 
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "type_lookup_table.h"
 #include "utf-inl.h"
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b52e2f2..a40e313 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -37,8 +37,9 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string.h"
 #include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utf-inl.h"
 
 #if defined(__APPLE__)
@@ -270,14 +271,14 @@
   }
 }
 
-std::string PrettyDescriptor(mirror::String* java_descriptor) {
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
   if (java_descriptor == nullptr) {
     return "null";
   }
   return PrettyDescriptor(java_descriptor->ToModifiedUtf8().c_str());
 }
 
-std::string PrettyDescriptor(mirror::Class* klass) {
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass) {
   if (klass == nullptr) {
     return "null";
   }
@@ -456,7 +457,7 @@
   return result;
 }
 
-std::string PrettyTypeOf(mirror::Object* obj) {
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj) {
   if (obj == nullptr) {
     return "null";
   }
@@ -471,7 +472,7 @@
   return result;
 }
 
-std::string PrettyClass(mirror::Class* c) {
+std::string PrettyClass(ObjPtr<mirror::Class> c) {
   if (c == nullptr) {
     return "null";
   }
@@ -482,7 +483,7 @@
   return result;
 }
 
-std::string PrettyClassAndClassLoader(mirror::Class* c) {
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c) {
   if (c == nullptr) {
     return "null";
   }
diff --git a/runtime/utils.h b/runtime/utils.h
index e65b947..ea9e8f7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -33,6 +33,7 @@
 #include "base/mutex.h"
 #include "base/stringpiece.h"
 #include "globals.h"
+#include "obj_ptr.h"
 #include "primitive.h"
 
 class BacktraceMap;
@@ -135,10 +136,10 @@
 // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
 // "[[I" would be "int[][]", "[Ljava/lang/String;" would be
 // "java.lang.String[]", and so forth.
-std::string PrettyDescriptor(mirror::String* descriptor)
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor)
     REQUIRES_SHARED(Locks::mutator_lock_);
 std::string PrettyDescriptor(const char* descriptor);
-std::string PrettyDescriptor(mirror::Class* klass)
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass)
     REQUIRES_SHARED(Locks::mutator_lock_);
 std::string PrettyDescriptor(Primitive::Type type);
 
@@ -158,7 +159,7 @@
 // So given an instance of java.lang.String, the output would
 // be "java.lang.String". Given an array of int, the output would be "int[]".
 // Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyTypeOf(mirror::Object* obj)
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Returns a human-readable form of the type at an index in the specified dex file.
@@ -167,11 +168,11 @@
 
 // Returns a human-readable form of the name of the given class.
 // Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyClass(mirror::Class* c)
+std::string PrettyClass(ObjPtr<mirror::Class> c)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Returns a human-readable form of the name of the given class with its class loader.
-std::string PrettyClassAndClassLoader(mirror::Class* c)
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Returns a human-readable version of the Java part of the access flags, e.g., "private static "
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 3ba20a4..ef42222 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -26,7 +26,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 
 #include "base/memory_tool.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 13ef043..87b6dc3 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -46,7 +46,7 @@
 #include "reg_type-inl.h"
 #include "register_line-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "verifier_deps.h"
 #include "handle_scope-inl.h"
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 646987a..837ee2d 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -22,7 +22,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "verifier_log_mode.h"
 
 namespace art {
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 3bc2acc..a84668b 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -27,7 +27,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reg_type_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 #include <limits>
 #include <sstream>
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index f2411b5..49dac26 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -24,7 +24,7 @@
 #include "common_runtime_test.h"
 #include "reg_type_cache-inl.h"
 #include "reg_type-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/verifier/verifier_deps_test.cc b/runtime/verifier/verifier_deps_test.cc
index bbaf59f..4533464 100644
--- a/runtime/verifier/verifier_deps_test.cc
+++ b/runtime/verifier/verifier_deps_test.cc
@@ -25,7 +25,7 @@
 #include "mirror/class_loader.h"
 #include "runtime.h"
 #include "thread.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace verifier {
@@ -58,7 +58,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_) {
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa->Decode<mirror::ClassLoader*>(class_loader_)));
+        hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_)));
     mirror::Class* klass = class_linker_->FindClass(Thread::Current(),
                                                     name.c_str(),
                                                     class_loader_handle);
@@ -84,8 +84,8 @@
 
     SetVerifierDeps(dex_files);
 
-    mirror::ClassLoader* loader = soa->Decode<mirror::ClassLoader*>(class_loader_);
-    class_linker_->RegisterDexFile(*dex_file_, loader);
+    ObjPtr<mirror::ClassLoader> loader = soa->Decode<mirror::ClassLoader>(class_loader_);
+    class_linker_->RegisterDexFile(*dex_file_, loader.Decode());
 
     klass_Main_ = FindClassByName("LMain;", soa);
     CHECK(klass_Main_ != nullptr);
@@ -97,7 +97,7 @@
 
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
     Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
 
     const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index e5216fb..4dcf58f 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -25,7 +25,7 @@
 #include "mirror/class.h"
 #include "mirror/throwable.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/test/004-ThreadStress/thread_stress.cc b/test/004-ThreadStress/thread_stress.cc
index 573c352..8ae3dfb 100644
--- a/test/004-ThreadStress/thread_stress.cc
+++ b/test/004-ThreadStress/thread_stress.cc
@@ -19,18 +19,18 @@
 #include "jni.h"
 #include "mirror/string.h"
 #include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
 extern "C" JNIEXPORT void JNICALL Java_Main_printString(JNIEnv*, jclass, jstring s) {
   ScopedObjectAccess soa(Thread::Current());
-  std::cout << soa.Decode<mirror::String*>(s)->ToModifiedUtf8();
+  std::cout << soa.Decode<mirror::String>(s)->ToModifiedUtf8();
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_printThrowable(JNIEnv*, jclass, jthrowable t) {
   ScopedObjectAccess soa(Thread::Current());
-  std::cout << soa.Decode<mirror::Throwable*>(t)->Dump();
+  std::cout << soa.Decode<mirror::Throwable>(t)->Dump();
 }
 
 }  // namespace art
diff --git a/test/004-UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc
index 3b0cf23..4f6ae5a 100644
--- a/test/004-UnsafeTest/unsafe_test.cc
+++ b/test/004-UnsafeTest/unsafe_test.cc
@@ -20,20 +20,20 @@
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
 extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
-  mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
   return mirror::Array::DataOffset(
       Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType())).Int32Value();
 }
 
 extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
-  mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
   return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType());
 }
 
diff --git a/test/054-uncaught/src/Main.java b/test/054-uncaught/src/Main.java
index 90a2311..688a2a4 100644
--- a/test/054-uncaught/src/Main.java
+++ b/test/054-uncaught/src/Main.java
@@ -41,7 +41,7 @@
         ThreadDeathHandler defHandler = new ThreadDeathHandler("DEFAULT");
         ThreadDeathHandler threadHandler = new ThreadDeathHandler("THREAD");
 
-        System.out.println("Test " + which);
+        System.err.println("Test " + which);
         switch (which) {
             case 1: {
                 Thread.setDefaultUncaughtExceptionHandler(defHandler);
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index c6a2e9a..56c0dcd 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -20,7 +20,7 @@
 #include "gc/space/image_space.h"
 #include "mirror/class-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
@@ -29,7 +29,7 @@
  public:
   static const OatFile::OatDexFile* getOatDexFile(jclass cls) {
     ScopedObjectAccess soa(Thread::Current());
-    mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+    ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
     const DexFile& dex_file = klass->GetDexFile();
     return dex_file.GetOatDexFile();
   }
diff --git a/test/1337-gc-coverage/gc_coverage.cc b/test/1337-gc-coverage/gc_coverage.cc
index 7cf30bd..1e60bd9 100644
--- a/test/1337-gc-coverage/gc_coverage.cc
+++ b/test/1337-gc-coverage/gc_coverage.cc
@@ -17,7 +17,7 @@
 #include "gc/heap.h"
 #include "jni.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -43,7 +43,7 @@
 
 extern "C" JNIEXPORT jlong JNICALL Java_Main_objectAddress(JNIEnv* env, jclass, jobject object) {
   ScopedObjectAccess soa(env);
-  return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+  return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
 }
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_supportCollectorTransition(JNIEnv*, jclass) {
diff --git a/test/148-multithread-gc-annotations/gc_coverage.cc b/test/148-multithread-gc-annotations/gc_coverage.cc
index 263eefd..cb12df4 100644
--- a/test/148-multithread-gc-annotations/gc_coverage.cc
+++ b/test/148-multithread-gc-annotations/gc_coverage.cc
@@ -17,7 +17,7 @@
 #include "gc/heap.h"
 #include "jni.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -35,7 +35,7 @@
 
 extern "C" JNIEXPORT jlong JNICALL Java_MovingGCThread_objectAddress(JNIEnv* env, jclass, jobject object) {
   ScopedObjectAccess soa(env);
-  return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+  return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
 }
 
 }  // namespace
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
index 5762754..9058af4 100644
--- a/test/454-get-vreg/get_vreg_jni.cc
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -123,7 +123,7 @@
 extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCall(JNIEnv*, jobject value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
   visitor.WalkStack();
   return visitor.found_method_index_;
 }
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index 08db775..f62a77d 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -139,7 +139,7 @@
     JNIEnv*, jclass value ATTRIBUTE_UNUSED, jobject main, jint int_value, jfloat float_value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  CHECK(soa.Decode<mirror::Object*>(main) == nullptr);
+  CHECK(soa.Decode<mirror::Object>(main) == nullptr);
   CHECK_EQ(int_value, 0);
   int32_t cast = bit_cast<int32_t, float>(float_value);
   CHECK_EQ(cast, 0);
diff --git a/test/461-get-reference-vreg/get_reference_vreg_jni.cc b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
index 8122c6d..7b1ab9c 100644
--- a/test/461-get-reference-vreg/get_reference_vreg_jni.cc
+++ b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
@@ -17,7 +17,7 @@
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -70,7 +70,7 @@
 extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCallRef(JNIEnv*, jobject value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
   visitor.WalkStack();
   return visitor.found_method_index_;
 }
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 3618b4f..d3a033b 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
index 1597c4a..3f2df29 100644
--- a/test/497-inlining-and-class-loader/clear_dex_cache.cc
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -17,7 +17,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -29,7 +29,7 @@
                                                                     jclass,
                                                                     jclass cls) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+  mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
   size_t num_methods = dex_cache->NumResolvedMethods();
   ArtMethod** methods = dex_cache->GetResolvedMethods();
   CHECK_EQ(num_methods != 0u, methods != nullptr);
@@ -43,7 +43,7 @@
     array = env->NewLongArray(num_methods);
   }
   CHECK(array != nullptr);
-  mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray*>(array);
+  mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray>(array).Decode();
   for (size_t i = 0; i != num_methods; ++i) {
     ArtMethod* method = mirror::DexCache::GetElementPtrSize(methods, i, kRuntimePointerSize);
     pointer_array->SetElementPtrSize(i, method, kRuntimePointerSize);
@@ -54,11 +54,11 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_restoreResolvedMethods(
     JNIEnv*, jclass, jclass cls, jobject old_cache) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+  mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
   size_t num_methods = dex_cache->NumResolvedMethods();
-  ArtMethod** methods = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods();
+  ArtMethod** methods = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetResolvedMethods();
   CHECK_EQ(num_methods != 0u, methods != nullptr);
-  mirror::PointerArray* old = soa.Decode<mirror::PointerArray*>(old_cache);
+  ObjPtr<mirror::PointerArray> old = soa.Decode<mirror::PointerArray>(old_cache);
   CHECK_EQ(methods != nullptr, old != nullptr);
   CHECK_EQ(num_methods, static_cast<size_t>(old->GetLength()));
   for (size_t i = 0; i != num_methods; ++i) {
diff --git a/test/543-env-long-ref/env_long_ref.cc b/test/543-env-long-ref/env_long_ref.cc
index 557def6..cd127ef 100644
--- a/test/543-env-long-ref/env_long_ref.cc
+++ b/test/543-env-long-ref/env_long_ref.cc
@@ -17,7 +17,7 @@
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -43,7 +43,7 @@
       uint32_t value = 0;
       CHECK(GetVReg(m, 1, kReferenceVReg, &value));
       CHECK_EQ(reinterpret_cast<mirror::Object*>(value),
-               soa_.Decode<mirror::Object*>(expected_value_));
+               soa_.Decode<mirror::Object>(expected_value_).Decode());
     }
     return true;
   }
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 89293cc..00c1b02 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -20,14 +20,14 @@
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
 
 namespace art {
 
 static void do_checks(jclass cls, const char* method_name) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   jit::Jit* jit = Runtime::Current()->GetJit();
   jit::JitCodeCache* code_cache = jit->GetCodeCache();
   ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
@@ -53,7 +53,7 @@
 
 static void allocate_profiling_info(jclass cls, const char* method_name) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
   ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
 }
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index adda3cc..50e8382 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -19,7 +19,7 @@
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "stack_map.h"
 
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index a265dce..bf3d812 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "oat_file_assistant.h"
 #include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread.h"
 
@@ -74,7 +74,7 @@
   ScopedUtfChars filename_chars(env, filename);
   CHECK(filename_chars.c_str() != nullptr);
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* dex_file = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetDexFile();
+  const DexFile* dex_file = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetDexFile();
   return ProfileSaver::HasSeenMethod(std::string(filename_chars.c_str()),
                                      dex_file,
                                      static_cast<uint16_t>(method_index));
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index a5bbf5f..78cc3fd 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -26,7 +26,7 @@
 #include "jni.h"
 #include "mirror/class.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -48,13 +48,13 @@
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, jclass, jclass c) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass_ptr = soa.Decode<mirror::Class*>(c);
+  ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c);
   for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
     if (space->IsImageSpace()) {
       auto* image_space = space->AsImageSpace();
       const auto& image_header = image_space->GetImageHeader();
       if (image_header.IsAppImage()) {
-        if (image_space->HasAddress(klass_ptr)) {
+        if (image_space->HasAddress(klass_ptr.Decode())) {
           return JNI_TRUE;
         }
       }
diff --git a/test/Android.bp b/test/Android.bp
index 72dcbba..628f377 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -110,7 +110,7 @@
                 "-Wl,-u,Java_MyClassNatives_sbar",
             ],
             shared_libs: [
-                "libcutils",
+                "liblog",
                 "libdl",
                 "libz",
             ],
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index fd1ba02..4248148 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "oat_quick_method_header.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread-inl.h"
 
@@ -35,7 +35,7 @@
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass cls) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
@@ -75,7 +75,7 @@
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   if (oat_dex_file == nullptr) {
@@ -134,7 +134,7 @@
 
     ScopedUtfChars chars(env, method_name);
     CHECK(chars.c_str() != nullptr);
-    method = soa.Decode<mirror::Class*>(cls)->FindDeclaredDirectMethodByName(
+    method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
         chars.c_str(), kRuntimePointerSize);
   }
 
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 85ea1c8..d2aacf0 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -21,7 +21,7 @@
 #include "mirror/class-inl.h"
 #include "nth_caller_visitor.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread-inl.h"
 
@@ -62,7 +62,7 @@
 static jboolean IsManaged(JNIEnv* env, jclass cls, size_t level) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   if (oat_dex_file == nullptr) {
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index c51cb0d..d8f42a2 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -404,6 +404,24 @@
   fi
 fi
 
+# Prevent test from silently falling back to interpreter in no-prebuild mode. This happens
+# when DEX_LOCATION path is too long, because vdex/odex filename is constructed by taking
+# full path to dex, stripping leading '/', appending '@classes.vdex' and changing every
+# remaining '/' into '@'.
+if [ "$HOST" = "y" ]; then
+  max_filename_size=$(getconf NAME_MAX $DEX_LOCATION)
+else
+  # There is no getconf on device, fallback to standard value. See NAME_MAX in kernel <linux/limits.h>
+  max_filename_size=255
+fi
+# Compute VDEX_NAME.
+DEX_LOCATION_STRIPPED="${DEX_LOCATION#/}"
+VDEX_NAME="${DEX_LOCATION_STRIPPED//\//@}@$TEST_NAME.jar@classes.vdex"
+if [ ${#VDEX_NAME} -gt $max_filename_size ]; then
+    echo  "Dex location path too long."
+    exit 1
+fi
+
 dex2oat_cmdline="true"
 mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
 strip_cmdline="true"
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index 54f9bb4..fd8415d 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -450,13 +450,13 @@
     os.mkdir(ddir)
     for f in glob('*.txt') + ['Test.java']:
       shutil.copy(f, ddir)
-    # Maybe run bisection bug search.
-    if (retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES and
-        not (self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2))):
-      self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
-    # Call reporting script.
-    if self._report_script:
-      self.RunReportScript(retc1, retc2, is_output_divergence)
+    if not (self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2)):
+      # Maybe run bisection bug search.
+      if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
+        self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
+      # Call reporting script.
+      if self._report_script:
+        self.RunReportScript(retc1, retc2, is_output_divergence)
 
   def RunReportScript(self, retc1, retc2, is_output_divergence):
     """Runs report script."""
diff --git a/tools/jfuzz/run_jfuzz_test_nightly.py b/tools/jfuzz/run_jfuzz_test_nightly.py
index cd338fb..29595f2 100755
--- a/tools/jfuzz/run_jfuzz_test_nightly.py
+++ b/tools/jfuzz/run_jfuzz_test_nightly.py
@@ -16,9 +16,14 @@
 
 import argparse
 import os
+import re
+import shutil
 import subprocess
 import sys
 
+from glob import glob
+
+from tempfile import mkdtemp
 from tempfile import TemporaryFile
 
 # Default arguments for run_jfuzz_test.py.
@@ -51,15 +56,29 @@
     for proc in processes:
       proc.kill()
   # Output results.
+  output_dirs = []
   for i, output_file in enumerate(output_files):
     output_file.seek(0)
     output_str = output_file.read().decode('ascii')
     output_file.close()
+    # Extract output directory. Example match: 'Directory : /tmp/tmp8ltpfjng'.
+    directory_match = re.search(r'Directory[^:]*: ([^\n]+)\n', output_str)
+    if directory_match:
+      output_dirs.append(directory_match.group(1))
     print('Tester', i)
     if output_str.find(SUCCESS_STRING) == NOT_FOUND:
       print(output_str)
     else:
       print(SUCCESS_STRING)
+  # Gather divergences.
+  global_out_dir = mkdtemp('jfuzz_nightly')
+  divergence_nr = 1
+  for out_dir in output_dirs:
+    for divergence_dir in glob(out_dir + '/divergence*/'):
+      shutil.copytree(divergence_dir,
+                      global_out_dir + '/divergence' + str(divergence_nr))
+      divergence_nr += 1
+  print('Global output directory:', global_out_dir)
 
 if __name__ == '__main__':
   main(sys.argv)