Merge "Revert "Revert "Revert "Revert "JIT root tables."""""
diff --git a/benchmark/const-class/info.txt b/benchmark/const-class/info.txt
new file mode 100644
index 0000000..ed0b827
--- /dev/null
+++ b/benchmark/const-class/info.txt
@@ -0,0 +1 @@
+Benchmarks for repeating const-class instructions in a loop.
diff --git a/benchmark/const-class/src/ConstClassBenchmark.java b/benchmark/const-class/src/ConstClassBenchmark.java
new file mode 100644
index 0000000..d45b49f
--- /dev/null
+++ b/benchmark/const-class/src/ConstClassBenchmark.java
@@ -0,0 +1,1071 @@
+/*
+ * 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 ConstClassBenchmark {
+    // Define 1025 classes with consecutive type indexes in the dex file.
+    // The tests below rely on the knowledge that ART uses the low 10 bits
+    // of the type index as the hash into DexCache types array.
+    // Note: n == n + 1024 (mod 2^10), n + 1 != n + 1023 (mod 2^10).
+    public static class TestClass_0000 {}
+    public static class TestClass_0001 {}
+    public static class TestClass_0002 {}
+    public static class TestClass_0003 {}
+    public static class TestClass_0004 {}
+    public static class TestClass_0005 {}
+    public static class TestClass_0006 {}
+    public static class TestClass_0007 {}
+    public static class TestClass_0008 {}
+    public static class TestClass_0009 {}
+    public static class TestClass_0010 {}
+    public static class TestClass_0011 {}
+    public static class TestClass_0012 {}
+    public static class TestClass_0013 {}
+    public static class TestClass_0014 {}
+    public static class TestClass_0015 {}
+    public static class TestClass_0016 {}
+    public static class TestClass_0017 {}
+    public static class TestClass_0018 {}
+    public static class TestClass_0019 {}
+    public static class TestClass_0020 {}
+    public static class TestClass_0021 {}
+    public static class TestClass_0022 {}
+    public static class TestClass_0023 {}
+    public static class TestClass_0024 {}
+    public static class TestClass_0025 {}
+    public static class TestClass_0026 {}
+    public static class TestClass_0027 {}
+    public static class TestClass_0028 {}
+    public static class TestClass_0029 {}
+    public static class TestClass_0030 {}
+    public static class TestClass_0031 {}
+    public static class TestClass_0032 {}
+    public static class TestClass_0033 {}
+    public static class TestClass_0034 {}
+    public static class TestClass_0035 {}
+    public static class TestClass_0036 {}
+    public static class TestClass_0037 {}
+    public static class TestClass_0038 {}
+    public static class TestClass_0039 {}
+    public static class TestClass_0040 {}
+    public static class TestClass_0041 {}
+    public static class TestClass_0042 {}
+    public static class TestClass_0043 {}
+    public static class TestClass_0044 {}
+    public static class TestClass_0045 {}
+    public static class TestClass_0046 {}
+    public static class TestClass_0047 {}
+    public static class TestClass_0048 {}
+    public static class TestClass_0049 {}
+    public static class TestClass_0050 {}
+    public static class TestClass_0051 {}
+    public static class TestClass_0052 {}
+    public static class TestClass_0053 {}
+    public static class TestClass_0054 {}
+    public static class TestClass_0055 {}
+    public static class TestClass_0056 {}
+    public static class TestClass_0057 {}
+    public static class TestClass_0058 {}
+    public static class TestClass_0059 {}
+    public static class TestClass_0060 {}
+    public static class TestClass_0061 {}
+    public static class TestClass_0062 {}
+    public static class TestClass_0063 {}
+    public static class TestClass_0064 {}
+    public static class TestClass_0065 {}
+    public static class TestClass_0066 {}
+    public static class TestClass_0067 {}
+    public static class TestClass_0068 {}
+    public static class TestClass_0069 {}
+    public static class TestClass_0070 {}
+    public static class TestClass_0071 {}
+    public static class TestClass_0072 {}
+    public static class TestClass_0073 {}
+    public static class TestClass_0074 {}
+    public static class TestClass_0075 {}
+    public static class TestClass_0076 {}
+    public static class TestClass_0077 {}
+    public static class TestClass_0078 {}
+    public static class TestClass_0079 {}
+    public static class TestClass_0080 {}
+    public static class TestClass_0081 {}
+    public static class TestClass_0082 {}
+    public static class TestClass_0083 {}
+    public static class TestClass_0084 {}
+    public static class TestClass_0085 {}
+    public static class TestClass_0086 {}
+    public static class TestClass_0087 {}
+    public static class TestClass_0088 {}
+    public static class TestClass_0089 {}
+    public static class TestClass_0090 {}
+    public static class TestClass_0091 {}
+    public static class TestClass_0092 {}
+    public static class TestClass_0093 {}
+    public static class TestClass_0094 {}
+    public static class TestClass_0095 {}
+    public static class TestClass_0096 {}
+    public static class TestClass_0097 {}
+    public static class TestClass_0098 {}
+    public static class TestClass_0099 {}
+    public static class TestClass_0100 {}
+    public static class TestClass_0101 {}
+    public static class TestClass_0102 {}
+    public static class TestClass_0103 {}
+    public static class TestClass_0104 {}
+    public static class TestClass_0105 {}
+    public static class TestClass_0106 {}
+    public static class TestClass_0107 {}
+    public static class TestClass_0108 {}
+    public static class TestClass_0109 {}
+    public static class TestClass_0110 {}
+    public static class TestClass_0111 {}
+    public static class TestClass_0112 {}
+    public static class TestClass_0113 {}
+    public static class TestClass_0114 {}
+    public static class TestClass_0115 {}
+    public static class TestClass_0116 {}
+    public static class TestClass_0117 {}
+    public static class TestClass_0118 {}
+    public static class TestClass_0119 {}
+    public static class TestClass_0120 {}
+    public static class TestClass_0121 {}
+    public static class TestClass_0122 {}
+    public static class TestClass_0123 {}
+    public static class TestClass_0124 {}
+    public static class TestClass_0125 {}
+    public static class TestClass_0126 {}
+    public static class TestClass_0127 {}
+    public static class TestClass_0128 {}
+    public static class TestClass_0129 {}
+    public static class TestClass_0130 {}
+    public static class TestClass_0131 {}
+    public static class TestClass_0132 {}
+    public static class TestClass_0133 {}
+    public static class TestClass_0134 {}
+    public static class TestClass_0135 {}
+    public static class TestClass_0136 {}
+    public static class TestClass_0137 {}
+    public static class TestClass_0138 {}
+    public static class TestClass_0139 {}
+    public static class TestClass_0140 {}
+    public static class TestClass_0141 {}
+    public static class TestClass_0142 {}
+    public static class TestClass_0143 {}
+    public static class TestClass_0144 {}
+    public static class TestClass_0145 {}
+    public static class TestClass_0146 {}
+    public static class TestClass_0147 {}
+    public static class TestClass_0148 {}
+    public static class TestClass_0149 {}
+    public static class TestClass_0150 {}
+    public static class TestClass_0151 {}
+    public static class TestClass_0152 {}
+    public static class TestClass_0153 {}
+    public static class TestClass_0154 {}
+    public static class TestClass_0155 {}
+    public static class TestClass_0156 {}
+    public static class TestClass_0157 {}
+    public static class TestClass_0158 {}
+    public static class TestClass_0159 {}
+    public static class TestClass_0160 {}
+    public static class TestClass_0161 {}
+    public static class TestClass_0162 {}
+    public static class TestClass_0163 {}
+    public static class TestClass_0164 {}
+    public static class TestClass_0165 {}
+    public static class TestClass_0166 {}
+    public static class TestClass_0167 {}
+    public static class TestClass_0168 {}
+    public static class TestClass_0169 {}
+    public static class TestClass_0170 {}
+    public static class TestClass_0171 {}
+    public static class TestClass_0172 {}
+    public static class TestClass_0173 {}
+    public static class TestClass_0174 {}
+    public static class TestClass_0175 {}
+    public static class TestClass_0176 {}
+    public static class TestClass_0177 {}
+    public static class TestClass_0178 {}
+    public static class TestClass_0179 {}
+    public static class TestClass_0180 {}
+    public static class TestClass_0181 {}
+    public static class TestClass_0182 {}
+    public static class TestClass_0183 {}
+    public static class TestClass_0184 {}
+    public static class TestClass_0185 {}
+    public static class TestClass_0186 {}
+    public static class TestClass_0187 {}
+    public static class TestClass_0188 {}
+    public static class TestClass_0189 {}
+    public static class TestClass_0190 {}
+    public static class TestClass_0191 {}
+    public static class TestClass_0192 {}
+    public static class TestClass_0193 {}
+    public static class TestClass_0194 {}
+    public static class TestClass_0195 {}
+    public static class TestClass_0196 {}
+    public static class TestClass_0197 {}
+    public static class TestClass_0198 {}
+    public static class TestClass_0199 {}
+    public static class TestClass_0200 {}
+    public static class TestClass_0201 {}
+    public static class TestClass_0202 {}
+    public static class TestClass_0203 {}
+    public static class TestClass_0204 {}
+    public static class TestClass_0205 {}
+    public static class TestClass_0206 {}
+    public static class TestClass_0207 {}
+    public static class TestClass_0208 {}
+    public static class TestClass_0209 {}
+    public static class TestClass_0210 {}
+    public static class TestClass_0211 {}
+    public static class TestClass_0212 {}
+    public static class TestClass_0213 {}
+    public static class TestClass_0214 {}
+    public static class TestClass_0215 {}
+    public static class TestClass_0216 {}
+    public static class TestClass_0217 {}
+    public static class TestClass_0218 {}
+    public static class TestClass_0219 {}
+    public static class TestClass_0220 {}
+    public static class TestClass_0221 {}
+    public static class TestClass_0222 {}
+    public static class TestClass_0223 {}
+    public static class TestClass_0224 {}
+    public static class TestClass_0225 {}
+    public static class TestClass_0226 {}
+    public static class TestClass_0227 {}
+    public static class TestClass_0228 {}
+    public static class TestClass_0229 {}
+    public static class TestClass_0230 {}
+    public static class TestClass_0231 {}
+    public static class TestClass_0232 {}
+    public static class TestClass_0233 {}
+    public static class TestClass_0234 {}
+    public static class TestClass_0235 {}
+    public static class TestClass_0236 {}
+    public static class TestClass_0237 {}
+    public static class TestClass_0238 {}
+    public static class TestClass_0239 {}
+    public static class TestClass_0240 {}
+    public static class TestClass_0241 {}
+    public static class TestClass_0242 {}
+    public static class TestClass_0243 {}
+    public static class TestClass_0244 {}
+    public static class TestClass_0245 {}
+    public static class TestClass_0246 {}
+    public static class TestClass_0247 {}
+    public static class TestClass_0248 {}
+    public static class TestClass_0249 {}
+    public static class TestClass_0250 {}
+    public static class TestClass_0251 {}
+    public static class TestClass_0252 {}
+    public static class TestClass_0253 {}
+    public static class TestClass_0254 {}
+    public static class TestClass_0255 {}
+    public static class TestClass_0256 {}
+    public static class TestClass_0257 {}
+    public static class TestClass_0258 {}
+    public static class TestClass_0259 {}
+    public static class TestClass_0260 {}
+    public static class TestClass_0261 {}
+    public static class TestClass_0262 {}
+    public static class TestClass_0263 {}
+    public static class TestClass_0264 {}
+    public static class TestClass_0265 {}
+    public static class TestClass_0266 {}
+    public static class TestClass_0267 {}
+    public static class TestClass_0268 {}
+    public static class TestClass_0269 {}
+    public static class TestClass_0270 {}
+    public static class TestClass_0271 {}
+    public static class TestClass_0272 {}
+    public static class TestClass_0273 {}
+    public static class TestClass_0274 {}
+    public static class TestClass_0275 {}
+    public static class TestClass_0276 {}
+    public static class TestClass_0277 {}
+    public static class TestClass_0278 {}
+    public static class TestClass_0279 {}
+    public static class TestClass_0280 {}
+    public static class TestClass_0281 {}
+    public static class TestClass_0282 {}
+    public static class TestClass_0283 {}
+    public static class TestClass_0284 {}
+    public static class TestClass_0285 {}
+    public static class TestClass_0286 {}
+    public static class TestClass_0287 {}
+    public static class TestClass_0288 {}
+    public static class TestClass_0289 {}
+    public static class TestClass_0290 {}
+    public static class TestClass_0291 {}
+    public static class TestClass_0292 {}
+    public static class TestClass_0293 {}
+    public static class TestClass_0294 {}
+    public static class TestClass_0295 {}
+    public static class TestClass_0296 {}
+    public static class TestClass_0297 {}
+    public static class TestClass_0298 {}
+    public static class TestClass_0299 {}
+    public static class TestClass_0300 {}
+    public static class TestClass_0301 {}
+    public static class TestClass_0302 {}
+    public static class TestClass_0303 {}
+    public static class TestClass_0304 {}
+    public static class TestClass_0305 {}
+    public static class TestClass_0306 {}
+    public static class TestClass_0307 {}
+    public static class TestClass_0308 {}
+    public static class TestClass_0309 {}
+    public static class TestClass_0310 {}
+    public static class TestClass_0311 {}
+    public static class TestClass_0312 {}
+    public static class TestClass_0313 {}
+    public static class TestClass_0314 {}
+    public static class TestClass_0315 {}
+    public static class TestClass_0316 {}
+    public static class TestClass_0317 {}
+    public static class TestClass_0318 {}
+    public static class TestClass_0319 {}
+    public static class TestClass_0320 {}
+    public static class TestClass_0321 {}
+    public static class TestClass_0322 {}
+    public static class TestClass_0323 {}
+    public static class TestClass_0324 {}
+    public static class TestClass_0325 {}
+    public static class TestClass_0326 {}
+    public static class TestClass_0327 {}
+    public static class TestClass_0328 {}
+    public static class TestClass_0329 {}
+    public static class TestClass_0330 {}
+    public static class TestClass_0331 {}
+    public static class TestClass_0332 {}
+    public static class TestClass_0333 {}
+    public static class TestClass_0334 {}
+    public static class TestClass_0335 {}
+    public static class TestClass_0336 {}
+    public static class TestClass_0337 {}
+    public static class TestClass_0338 {}
+    public static class TestClass_0339 {}
+    public static class TestClass_0340 {}
+    public static class TestClass_0341 {}
+    public static class TestClass_0342 {}
+    public static class TestClass_0343 {}
+    public static class TestClass_0344 {}
+    public static class TestClass_0345 {}
+    public static class TestClass_0346 {}
+    public static class TestClass_0347 {}
+    public static class TestClass_0348 {}
+    public static class TestClass_0349 {}
+    public static class TestClass_0350 {}
+    public static class TestClass_0351 {}
+    public static class TestClass_0352 {}
+    public static class TestClass_0353 {}
+    public static class TestClass_0354 {}
+    public static class TestClass_0355 {}
+    public static class TestClass_0356 {}
+    public static class TestClass_0357 {}
+    public static class TestClass_0358 {}
+    public static class TestClass_0359 {}
+    public static class TestClass_0360 {}
+    public static class TestClass_0361 {}
+    public static class TestClass_0362 {}
+    public static class TestClass_0363 {}
+    public static class TestClass_0364 {}
+    public static class TestClass_0365 {}
+    public static class TestClass_0366 {}
+    public static class TestClass_0367 {}
+    public static class TestClass_0368 {}
+    public static class TestClass_0369 {}
+    public static class TestClass_0370 {}
+    public static class TestClass_0371 {}
+    public static class TestClass_0372 {}
+    public static class TestClass_0373 {}
+    public static class TestClass_0374 {}
+    public static class TestClass_0375 {}
+    public static class TestClass_0376 {}
+    public static class TestClass_0377 {}
+    public static class TestClass_0378 {}
+    public static class TestClass_0379 {}
+    public static class TestClass_0380 {}
+    public static class TestClass_0381 {}
+    public static class TestClass_0382 {}
+    public static class TestClass_0383 {}
+    public static class TestClass_0384 {}
+    public static class TestClass_0385 {}
+    public static class TestClass_0386 {}
+    public static class TestClass_0387 {}
+    public static class TestClass_0388 {}
+    public static class TestClass_0389 {}
+    public static class TestClass_0390 {}
+    public static class TestClass_0391 {}
+    public static class TestClass_0392 {}
+    public static class TestClass_0393 {}
+    public static class TestClass_0394 {}
+    public static class TestClass_0395 {}
+    public static class TestClass_0396 {}
+    public static class TestClass_0397 {}
+    public static class TestClass_0398 {}
+    public static class TestClass_0399 {}
+    public static class TestClass_0400 {}
+    public static class TestClass_0401 {}
+    public static class TestClass_0402 {}
+    public static class TestClass_0403 {}
+    public static class TestClass_0404 {}
+    public static class TestClass_0405 {}
+    public static class TestClass_0406 {}
+    public static class TestClass_0407 {}
+    public static class TestClass_0408 {}
+    public static class TestClass_0409 {}
+    public static class TestClass_0410 {}
+    public static class TestClass_0411 {}
+    public static class TestClass_0412 {}
+    public static class TestClass_0413 {}
+    public static class TestClass_0414 {}
+    public static class TestClass_0415 {}
+    public static class TestClass_0416 {}
+    public static class TestClass_0417 {}
+    public static class TestClass_0418 {}
+    public static class TestClass_0419 {}
+    public static class TestClass_0420 {}
+    public static class TestClass_0421 {}
+    public static class TestClass_0422 {}
+    public static class TestClass_0423 {}
+    public static class TestClass_0424 {}
+    public static class TestClass_0425 {}
+    public static class TestClass_0426 {}
+    public static class TestClass_0427 {}
+    public static class TestClass_0428 {}
+    public static class TestClass_0429 {}
+    public static class TestClass_0430 {}
+    public static class TestClass_0431 {}
+    public static class TestClass_0432 {}
+    public static class TestClass_0433 {}
+    public static class TestClass_0434 {}
+    public static class TestClass_0435 {}
+    public static class TestClass_0436 {}
+    public static class TestClass_0437 {}
+    public static class TestClass_0438 {}
+    public static class TestClass_0439 {}
+    public static class TestClass_0440 {}
+    public static class TestClass_0441 {}
+    public static class TestClass_0442 {}
+    public static class TestClass_0443 {}
+    public static class TestClass_0444 {}
+    public static class TestClass_0445 {}
+    public static class TestClass_0446 {}
+    public static class TestClass_0447 {}
+    public static class TestClass_0448 {}
+    public static class TestClass_0449 {}
+    public static class TestClass_0450 {}
+    public static class TestClass_0451 {}
+    public static class TestClass_0452 {}
+    public static class TestClass_0453 {}
+    public static class TestClass_0454 {}
+    public static class TestClass_0455 {}
+    public static class TestClass_0456 {}
+    public static class TestClass_0457 {}
+    public static class TestClass_0458 {}
+    public static class TestClass_0459 {}
+    public static class TestClass_0460 {}
+    public static class TestClass_0461 {}
+    public static class TestClass_0462 {}
+    public static class TestClass_0463 {}
+    public static class TestClass_0464 {}
+    public static class TestClass_0465 {}
+    public static class TestClass_0466 {}
+    public static class TestClass_0467 {}
+    public static class TestClass_0468 {}
+    public static class TestClass_0469 {}
+    public static class TestClass_0470 {}
+    public static class TestClass_0471 {}
+    public static class TestClass_0472 {}
+    public static class TestClass_0473 {}
+    public static class TestClass_0474 {}
+    public static class TestClass_0475 {}
+    public static class TestClass_0476 {}
+    public static class TestClass_0477 {}
+    public static class TestClass_0478 {}
+    public static class TestClass_0479 {}
+    public static class TestClass_0480 {}
+    public static class TestClass_0481 {}
+    public static class TestClass_0482 {}
+    public static class TestClass_0483 {}
+    public static class TestClass_0484 {}
+    public static class TestClass_0485 {}
+    public static class TestClass_0486 {}
+    public static class TestClass_0487 {}
+    public static class TestClass_0488 {}
+    public static class TestClass_0489 {}
+    public static class TestClass_0490 {}
+    public static class TestClass_0491 {}
+    public static class TestClass_0492 {}
+    public static class TestClass_0493 {}
+    public static class TestClass_0494 {}
+    public static class TestClass_0495 {}
+    public static class TestClass_0496 {}
+    public static class TestClass_0497 {}
+    public static class TestClass_0498 {}
+    public static class TestClass_0499 {}
+    public static class TestClass_0500 {}
+    public static class TestClass_0501 {}
+    public static class TestClass_0502 {}
+    public static class TestClass_0503 {}
+    public static class TestClass_0504 {}
+    public static class TestClass_0505 {}
+    public static class TestClass_0506 {}
+    public static class TestClass_0507 {}
+    public static class TestClass_0508 {}
+    public static class TestClass_0509 {}
+    public static class TestClass_0510 {}
+    public static class TestClass_0511 {}
+    public static class TestClass_0512 {}
+    public static class TestClass_0513 {}
+    public static class TestClass_0514 {}
+    public static class TestClass_0515 {}
+    public static class TestClass_0516 {}
+    public static class TestClass_0517 {}
+    public static class TestClass_0518 {}
+    public static class TestClass_0519 {}
+    public static class TestClass_0520 {}
+    public static class TestClass_0521 {}
+    public static class TestClass_0522 {}
+    public static class TestClass_0523 {}
+    public static class TestClass_0524 {}
+    public static class TestClass_0525 {}
+    public static class TestClass_0526 {}
+    public static class TestClass_0527 {}
+    public static class TestClass_0528 {}
+    public static class TestClass_0529 {}
+    public static class TestClass_0530 {}
+    public static class TestClass_0531 {}
+    public static class TestClass_0532 {}
+    public static class TestClass_0533 {}
+    public static class TestClass_0534 {}
+    public static class TestClass_0535 {}
+    public static class TestClass_0536 {}
+    public static class TestClass_0537 {}
+    public static class TestClass_0538 {}
+    public static class TestClass_0539 {}
+    public static class TestClass_0540 {}
+    public static class TestClass_0541 {}
+    public static class TestClass_0542 {}
+    public static class TestClass_0543 {}
+    public static class TestClass_0544 {}
+    public static class TestClass_0545 {}
+    public static class TestClass_0546 {}
+    public static class TestClass_0547 {}
+    public static class TestClass_0548 {}
+    public static class TestClass_0549 {}
+    public static class TestClass_0550 {}
+    public static class TestClass_0551 {}
+    public static class TestClass_0552 {}
+    public static class TestClass_0553 {}
+    public static class TestClass_0554 {}
+    public static class TestClass_0555 {}
+    public static class TestClass_0556 {}
+    public static class TestClass_0557 {}
+    public static class TestClass_0558 {}
+    public static class TestClass_0559 {}
+    public static class TestClass_0560 {}
+    public static class TestClass_0561 {}
+    public static class TestClass_0562 {}
+    public static class TestClass_0563 {}
+    public static class TestClass_0564 {}
+    public static class TestClass_0565 {}
+    public static class TestClass_0566 {}
+    public static class TestClass_0567 {}
+    public static class TestClass_0568 {}
+    public static class TestClass_0569 {}
+    public static class TestClass_0570 {}
+    public static class TestClass_0571 {}
+    public static class TestClass_0572 {}
+    public static class TestClass_0573 {}
+    public static class TestClass_0574 {}
+    public static class TestClass_0575 {}
+    public static class TestClass_0576 {}
+    public static class TestClass_0577 {}
+    public static class TestClass_0578 {}
+    public static class TestClass_0579 {}
+    public static class TestClass_0580 {}
+    public static class TestClass_0581 {}
+    public static class TestClass_0582 {}
+    public static class TestClass_0583 {}
+    public static class TestClass_0584 {}
+    public static class TestClass_0585 {}
+    public static class TestClass_0586 {}
+    public static class TestClass_0587 {}
+    public static class TestClass_0588 {}
+    public static class TestClass_0589 {}
+    public static class TestClass_0590 {}
+    public static class TestClass_0591 {}
+    public static class TestClass_0592 {}
+    public static class TestClass_0593 {}
+    public static class TestClass_0594 {}
+    public static class TestClass_0595 {}
+    public static class TestClass_0596 {}
+    public static class TestClass_0597 {}
+    public static class TestClass_0598 {}
+    public static class TestClass_0599 {}
+    public static class TestClass_0600 {}
+    public static class TestClass_0601 {}
+    public static class TestClass_0602 {}
+    public static class TestClass_0603 {}
+    public static class TestClass_0604 {}
+    public static class TestClass_0605 {}
+    public static class TestClass_0606 {}
+    public static class TestClass_0607 {}
+    public static class TestClass_0608 {}
+    public static class TestClass_0609 {}
+    public static class TestClass_0610 {}
+    public static class TestClass_0611 {}
+    public static class TestClass_0612 {}
+    public static class TestClass_0613 {}
+    public static class TestClass_0614 {}
+    public static class TestClass_0615 {}
+    public static class TestClass_0616 {}
+    public static class TestClass_0617 {}
+    public static class TestClass_0618 {}
+    public static class TestClass_0619 {}
+    public static class TestClass_0620 {}
+    public static class TestClass_0621 {}
+    public static class TestClass_0622 {}
+    public static class TestClass_0623 {}
+    public static class TestClass_0624 {}
+    public static class TestClass_0625 {}
+    public static class TestClass_0626 {}
+    public static class TestClass_0627 {}
+    public static class TestClass_0628 {}
+    public static class TestClass_0629 {}
+    public static class TestClass_0630 {}
+    public static class TestClass_0631 {}
+    public static class TestClass_0632 {}
+    public static class TestClass_0633 {}
+    public static class TestClass_0634 {}
+    public static class TestClass_0635 {}
+    public static class TestClass_0636 {}
+    public static class TestClass_0637 {}
+    public static class TestClass_0638 {}
+    public static class TestClass_0639 {}
+    public static class TestClass_0640 {}
+    public static class TestClass_0641 {}
+    public static class TestClass_0642 {}
+    public static class TestClass_0643 {}
+    public static class TestClass_0644 {}
+    public static class TestClass_0645 {}
+    public static class TestClass_0646 {}
+    public static class TestClass_0647 {}
+    public static class TestClass_0648 {}
+    public static class TestClass_0649 {}
+    public static class TestClass_0650 {}
+    public static class TestClass_0651 {}
+    public static class TestClass_0652 {}
+    public static class TestClass_0653 {}
+    public static class TestClass_0654 {}
+    public static class TestClass_0655 {}
+    public static class TestClass_0656 {}
+    public static class TestClass_0657 {}
+    public static class TestClass_0658 {}
+    public static class TestClass_0659 {}
+    public static class TestClass_0660 {}
+    public static class TestClass_0661 {}
+    public static class TestClass_0662 {}
+    public static class TestClass_0663 {}
+    public static class TestClass_0664 {}
+    public static class TestClass_0665 {}
+    public static class TestClass_0666 {}
+    public static class TestClass_0667 {}
+    public static class TestClass_0668 {}
+    public static class TestClass_0669 {}
+    public static class TestClass_0670 {}
+    public static class TestClass_0671 {}
+    public static class TestClass_0672 {}
+    public static class TestClass_0673 {}
+    public static class TestClass_0674 {}
+    public static class TestClass_0675 {}
+    public static class TestClass_0676 {}
+    public static class TestClass_0677 {}
+    public static class TestClass_0678 {}
+    public static class TestClass_0679 {}
+    public static class TestClass_0680 {}
+    public static class TestClass_0681 {}
+    public static class TestClass_0682 {}
+    public static class TestClass_0683 {}
+    public static class TestClass_0684 {}
+    public static class TestClass_0685 {}
+    public static class TestClass_0686 {}
+    public static class TestClass_0687 {}
+    public static class TestClass_0688 {}
+    public static class TestClass_0689 {}
+    public static class TestClass_0690 {}
+    public static class TestClass_0691 {}
+    public static class TestClass_0692 {}
+    public static class TestClass_0693 {}
+    public static class TestClass_0694 {}
+    public static class TestClass_0695 {}
+    public static class TestClass_0696 {}
+    public static class TestClass_0697 {}
+    public static class TestClass_0698 {}
+    public static class TestClass_0699 {}
+    public static class TestClass_0700 {}
+    public static class TestClass_0701 {}
+    public static class TestClass_0702 {}
+    public static class TestClass_0703 {}
+    public static class TestClass_0704 {}
+    public static class TestClass_0705 {}
+    public static class TestClass_0706 {}
+    public static class TestClass_0707 {}
+    public static class TestClass_0708 {}
+    public static class TestClass_0709 {}
+    public static class TestClass_0710 {}
+    public static class TestClass_0711 {}
+    public static class TestClass_0712 {}
+    public static class TestClass_0713 {}
+    public static class TestClass_0714 {}
+    public static class TestClass_0715 {}
+    public static class TestClass_0716 {}
+    public static class TestClass_0717 {}
+    public static class TestClass_0718 {}
+    public static class TestClass_0719 {}
+    public static class TestClass_0720 {}
+    public static class TestClass_0721 {}
+    public static class TestClass_0722 {}
+    public static class TestClass_0723 {}
+    public static class TestClass_0724 {}
+    public static class TestClass_0725 {}
+    public static class TestClass_0726 {}
+    public static class TestClass_0727 {}
+    public static class TestClass_0728 {}
+    public static class TestClass_0729 {}
+    public static class TestClass_0730 {}
+    public static class TestClass_0731 {}
+    public static class TestClass_0732 {}
+    public static class TestClass_0733 {}
+    public static class TestClass_0734 {}
+    public static class TestClass_0735 {}
+    public static class TestClass_0736 {}
+    public static class TestClass_0737 {}
+    public static class TestClass_0738 {}
+    public static class TestClass_0739 {}
+    public static class TestClass_0740 {}
+    public static class TestClass_0741 {}
+    public static class TestClass_0742 {}
+    public static class TestClass_0743 {}
+    public static class TestClass_0744 {}
+    public static class TestClass_0745 {}
+    public static class TestClass_0746 {}
+    public static class TestClass_0747 {}
+    public static class TestClass_0748 {}
+    public static class TestClass_0749 {}
+    public static class TestClass_0750 {}
+    public static class TestClass_0751 {}
+    public static class TestClass_0752 {}
+    public static class TestClass_0753 {}
+    public static class TestClass_0754 {}
+    public static class TestClass_0755 {}
+    public static class TestClass_0756 {}
+    public static class TestClass_0757 {}
+    public static class TestClass_0758 {}
+    public static class TestClass_0759 {}
+    public static class TestClass_0760 {}
+    public static class TestClass_0761 {}
+    public static class TestClass_0762 {}
+    public static class TestClass_0763 {}
+    public static class TestClass_0764 {}
+    public static class TestClass_0765 {}
+    public static class TestClass_0766 {}
+    public static class TestClass_0767 {}
+    public static class TestClass_0768 {}
+    public static class TestClass_0769 {}
+    public static class TestClass_0770 {}
+    public static class TestClass_0771 {}
+    public static class TestClass_0772 {}
+    public static class TestClass_0773 {}
+    public static class TestClass_0774 {}
+    public static class TestClass_0775 {}
+    public static class TestClass_0776 {}
+    public static class TestClass_0777 {}
+    public static class TestClass_0778 {}
+    public static class TestClass_0779 {}
+    public static class TestClass_0780 {}
+    public static class TestClass_0781 {}
+    public static class TestClass_0782 {}
+    public static class TestClass_0783 {}
+    public static class TestClass_0784 {}
+    public static class TestClass_0785 {}
+    public static class TestClass_0786 {}
+    public static class TestClass_0787 {}
+    public static class TestClass_0788 {}
+    public static class TestClass_0789 {}
+    public static class TestClass_0790 {}
+    public static class TestClass_0791 {}
+    public static class TestClass_0792 {}
+    public static class TestClass_0793 {}
+    public static class TestClass_0794 {}
+    public static class TestClass_0795 {}
+    public static class TestClass_0796 {}
+    public static class TestClass_0797 {}
+    public static class TestClass_0798 {}
+    public static class TestClass_0799 {}
+    public static class TestClass_0800 {}
+    public static class TestClass_0801 {}
+    public static class TestClass_0802 {}
+    public static class TestClass_0803 {}
+    public static class TestClass_0804 {}
+    public static class TestClass_0805 {}
+    public static class TestClass_0806 {}
+    public static class TestClass_0807 {}
+    public static class TestClass_0808 {}
+    public static class TestClass_0809 {}
+    public static class TestClass_0810 {}
+    public static class TestClass_0811 {}
+    public static class TestClass_0812 {}
+    public static class TestClass_0813 {}
+    public static class TestClass_0814 {}
+    public static class TestClass_0815 {}
+    public static class TestClass_0816 {}
+    public static class TestClass_0817 {}
+    public static class TestClass_0818 {}
+    public static class TestClass_0819 {}
+    public static class TestClass_0820 {}
+    public static class TestClass_0821 {}
+    public static class TestClass_0822 {}
+    public static class TestClass_0823 {}
+    public static class TestClass_0824 {}
+    public static class TestClass_0825 {}
+    public static class TestClass_0826 {}
+    public static class TestClass_0827 {}
+    public static class TestClass_0828 {}
+    public static class TestClass_0829 {}
+    public static class TestClass_0830 {}
+    public static class TestClass_0831 {}
+    public static class TestClass_0832 {}
+    public static class TestClass_0833 {}
+    public static class TestClass_0834 {}
+    public static class TestClass_0835 {}
+    public static class TestClass_0836 {}
+    public static class TestClass_0837 {}
+    public static class TestClass_0838 {}
+    public static class TestClass_0839 {}
+    public static class TestClass_0840 {}
+    public static class TestClass_0841 {}
+    public static class TestClass_0842 {}
+    public static class TestClass_0843 {}
+    public static class TestClass_0844 {}
+    public static class TestClass_0845 {}
+    public static class TestClass_0846 {}
+    public static class TestClass_0847 {}
+    public static class TestClass_0848 {}
+    public static class TestClass_0849 {}
+    public static class TestClass_0850 {}
+    public static class TestClass_0851 {}
+    public static class TestClass_0852 {}
+    public static class TestClass_0853 {}
+    public static class TestClass_0854 {}
+    public static class TestClass_0855 {}
+    public static class TestClass_0856 {}
+    public static class TestClass_0857 {}
+    public static class TestClass_0858 {}
+    public static class TestClass_0859 {}
+    public static class TestClass_0860 {}
+    public static class TestClass_0861 {}
+    public static class TestClass_0862 {}
+    public static class TestClass_0863 {}
+    public static class TestClass_0864 {}
+    public static class TestClass_0865 {}
+    public static class TestClass_0866 {}
+    public static class TestClass_0867 {}
+    public static class TestClass_0868 {}
+    public static class TestClass_0869 {}
+    public static class TestClass_0870 {}
+    public static class TestClass_0871 {}
+    public static class TestClass_0872 {}
+    public static class TestClass_0873 {}
+    public static class TestClass_0874 {}
+    public static class TestClass_0875 {}
+    public static class TestClass_0876 {}
+    public static class TestClass_0877 {}
+    public static class TestClass_0878 {}
+    public static class TestClass_0879 {}
+    public static class TestClass_0880 {}
+    public static class TestClass_0881 {}
+    public static class TestClass_0882 {}
+    public static class TestClass_0883 {}
+    public static class TestClass_0884 {}
+    public static class TestClass_0885 {}
+    public static class TestClass_0886 {}
+    public static class TestClass_0887 {}
+    public static class TestClass_0888 {}
+    public static class TestClass_0889 {}
+    public static class TestClass_0890 {}
+    public static class TestClass_0891 {}
+    public static class TestClass_0892 {}
+    public static class TestClass_0893 {}
+    public static class TestClass_0894 {}
+    public static class TestClass_0895 {}
+    public static class TestClass_0896 {}
+    public static class TestClass_0897 {}
+    public static class TestClass_0898 {}
+    public static class TestClass_0899 {}
+    public static class TestClass_0900 {}
+    public static class TestClass_0901 {}
+    public static class TestClass_0902 {}
+    public static class TestClass_0903 {}
+    public static class TestClass_0904 {}
+    public static class TestClass_0905 {}
+    public static class TestClass_0906 {}
+    public static class TestClass_0907 {}
+    public static class TestClass_0908 {}
+    public static class TestClass_0909 {}
+    public static class TestClass_0910 {}
+    public static class TestClass_0911 {}
+    public static class TestClass_0912 {}
+    public static class TestClass_0913 {}
+    public static class TestClass_0914 {}
+    public static class TestClass_0915 {}
+    public static class TestClass_0916 {}
+    public static class TestClass_0917 {}
+    public static class TestClass_0918 {}
+    public static class TestClass_0919 {}
+    public static class TestClass_0920 {}
+    public static class TestClass_0921 {}
+    public static class TestClass_0922 {}
+    public static class TestClass_0923 {}
+    public static class TestClass_0924 {}
+    public static class TestClass_0925 {}
+    public static class TestClass_0926 {}
+    public static class TestClass_0927 {}
+    public static class TestClass_0928 {}
+    public static class TestClass_0929 {}
+    public static class TestClass_0930 {}
+    public static class TestClass_0931 {}
+    public static class TestClass_0932 {}
+    public static class TestClass_0933 {}
+    public static class TestClass_0934 {}
+    public static class TestClass_0935 {}
+    public static class TestClass_0936 {}
+    public static class TestClass_0937 {}
+    public static class TestClass_0938 {}
+    public static class TestClass_0939 {}
+    public static class TestClass_0940 {}
+    public static class TestClass_0941 {}
+    public static class TestClass_0942 {}
+    public static class TestClass_0943 {}
+    public static class TestClass_0944 {}
+    public static class TestClass_0945 {}
+    public static class TestClass_0946 {}
+    public static class TestClass_0947 {}
+    public static class TestClass_0948 {}
+    public static class TestClass_0949 {}
+    public static class TestClass_0950 {}
+    public static class TestClass_0951 {}
+    public static class TestClass_0952 {}
+    public static class TestClass_0953 {}
+    public static class TestClass_0954 {}
+    public static class TestClass_0955 {}
+    public static class TestClass_0956 {}
+    public static class TestClass_0957 {}
+    public static class TestClass_0958 {}
+    public static class TestClass_0959 {}
+    public static class TestClass_0960 {}
+    public static class TestClass_0961 {}
+    public static class TestClass_0962 {}
+    public static class TestClass_0963 {}
+    public static class TestClass_0964 {}
+    public static class TestClass_0965 {}
+    public static class TestClass_0966 {}
+    public static class TestClass_0967 {}
+    public static class TestClass_0968 {}
+    public static class TestClass_0969 {}
+    public static class TestClass_0970 {}
+    public static class TestClass_0971 {}
+    public static class TestClass_0972 {}
+    public static class TestClass_0973 {}
+    public static class TestClass_0974 {}
+    public static class TestClass_0975 {}
+    public static class TestClass_0976 {}
+    public static class TestClass_0977 {}
+    public static class TestClass_0978 {}
+    public static class TestClass_0979 {}
+    public static class TestClass_0980 {}
+    public static class TestClass_0981 {}
+    public static class TestClass_0982 {}
+    public static class TestClass_0983 {}
+    public static class TestClass_0984 {}
+    public static class TestClass_0985 {}
+    public static class TestClass_0986 {}
+    public static class TestClass_0987 {}
+    public static class TestClass_0988 {}
+    public static class TestClass_0989 {}
+    public static class TestClass_0990 {}
+    public static class TestClass_0991 {}
+    public static class TestClass_0992 {}
+    public static class TestClass_0993 {}
+    public static class TestClass_0994 {}
+    public static class TestClass_0995 {}
+    public static class TestClass_0996 {}
+    public static class TestClass_0997 {}
+    public static class TestClass_0998 {}
+    public static class TestClass_0999 {}
+    public static class TestClass_1000 {}
+    public static class TestClass_1001 {}
+    public static class TestClass_1002 {}
+    public static class TestClass_1003 {}
+    public static class TestClass_1004 {}
+    public static class TestClass_1005 {}
+    public static class TestClass_1006 {}
+    public static class TestClass_1007 {}
+    public static class TestClass_1008 {}
+    public static class TestClass_1009 {}
+    public static class TestClass_1010 {}
+    public static class TestClass_1011 {}
+    public static class TestClass_1012 {}
+    public static class TestClass_1013 {}
+    public static class TestClass_1014 {}
+    public static class TestClass_1015 {}
+    public static class TestClass_1016 {}
+    public static class TestClass_1017 {}
+    public static class TestClass_1018 {}
+    public static class TestClass_1019 {}
+    public static class TestClass_1020 {}
+    public static class TestClass_1021 {}
+    public static class TestClass_1022 {}
+    public static class TestClass_1023 {}
+    public static class TestClass_1024 {}
+
+    public void timeConstClassWithConflict(int count) {
+        Class<?> class0001 = TestClass_0001.class;
+        for (int i = 0; i < count; ++i) {
+            $noinline$foo(class0001);  // Prevent LICM on the TestClass_xxxx.class below.
+            $noinline$foo(TestClass_0000.class);
+            $noinline$foo(TestClass_1024.class);
+        }
+    }
+
+    public void timeConstClassWithoutConflict(int count) {
+        Class<?> class0000 = TestClass_0000.class;
+        for (int i = 0; i < count; ++i) {
+            $noinline$foo(class0000);  // Prevent LICM on the TestClass_xxxx.class below.
+            $noinline$foo(TestClass_0001.class);
+            $noinline$foo(TestClass_1023.class);
+        }
+    }
+
+    static void $noinline$foo(Class<?> s) {
+        if (doThrow) { throw new Error(); }
+    }
+
+    public static boolean doThrow = false;
+}
diff --git a/benchmark/const-string/src/ConstStringBenchmark.java b/benchmark/const-string/src/ConstStringBenchmark.java
index 2beb0a4..2359a5f 100644
--- a/benchmark/const-string/src/ConstStringBenchmark.java
+++ b/benchmark/const-string/src/ConstStringBenchmark.java
@@ -18,6 +18,7 @@
     // 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.
+    // Note: n == n + 1024 (mod 2^10), n + 1 != n + 1023 (mod 2^10).
     public static final String string_0000 = "TestString_0000";
     public static final String string_0001 = "TestString_0001";
     public static final String string_0002 = "TestString_0002";
@@ -1045,21 +1046,21 @@
     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");
-      }
+        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");
-      }
+        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(); }
+        if (doThrow) { throw new Error(); }
     }
 
     public static boolean doThrow = false;
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c785bef..4fce235 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -25,6 +25,7 @@
 GTEST_DEX_DIRECTORIES := \
   AbstractMethod \
   AllFields \
+  DexToDexDecompiler \
   ExceptionHandle \
   GetMethodSignature \
   ImageLayoutA \
@@ -106,6 +107,7 @@
 ART_GTEST_transaction_test_DEX_DEPS := Transaction
 ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup
 ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps MultiDex
+ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler
 
 # The elf writer test has dependencies on core.oat.
 ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 3f55eef..156ca9e 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -496,11 +496,7 @@
 struct XGcOption {
   // These defaults are used when the command line arguments for -Xgc:
   // are either omitted completely or partially.
-  gc::CollectorType collector_type_ = kUseReadBarrier ?
-                                           // If RB is enabled (currently a build-time decision),
-                                           // use CC as the default GC.
-                                           gc::kCollectorTypeCC :
-                                           gc::kCollectorTypeDefault;
+  gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
   bool verify_pre_gc_heap_ = false;
   bool verify_pre_sweeping_heap_ = kIsDebugBuild;
   bool verify_post_gc_heap_ = false;
@@ -580,10 +576,6 @@
     : background_collector_type_(background_collector_type) {}
   BackgroundGcOption()
     : background_collector_type_(gc::kCollectorTypeNone) {
-
-    if (kUseReadBarrier) {
-      background_collector_type_ = gc::kCollectorTypeCCBackground;  // Background compaction for CC.
-    }
   }
 
   operator gc::CollectorType() const { return background_collector_type_; }
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 6edb639..e2a450d 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -28,6 +28,7 @@
         "compiled_method.cc",
         "debug/elf_debug_writer.cc",
         "dex/dex_to_dex_compiler.cc",
+        "dex/dex_to_dex_decompiler.cc",
         "dex/verified_method.cc",
         "dex/verification_results.cc",
         "dex/quick_compiler_callbacks.cc",
@@ -312,6 +313,7 @@
     srcs: [
         "compiled_method_test.cc",
         "debug/dwarf/dwarf_test.cc",
+        "dex/dex_to_dex_decompiler_test.cc",
         "driver/compiled_method_storage_test.cc",
         "driver/compiler_driver_test.cc",
         "elf_writer_test.cc",
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 9c1d72b..cf69f46 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -233,6 +233,8 @@
                  << " by replacing it with 2 NOPs at dex pc "
                  << StringPrintf("0x%x", dex_pc) << " in method "
                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
+  quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
+  quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
   // We are modifying 4 consecutive bytes.
   inst->SetOpcode(Instruction::NOP);
   inst->SetVRegA_10x(0u);  // keep compliant with verifier.
diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h
index 3fad6d4..0a00d45 100644
--- a/compiler/dex/dex_to_dex_compiler.h
+++ b/compiler/dex/dex_to_dex_compiler.h
@@ -17,8 +17,6 @@
 #ifndef ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
 #define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
 
-#include "jni.h"
-
 #include "dex_file.h"
 #include "invoke_type.h"
 
diff --git a/compiler/dex/dex_to_dex_decompiler.cc b/compiler/dex/dex_to_dex_decompiler.cc
new file mode 100644
index 0000000..051125e
--- /dev/null
+++ b/compiler/dex/dex_to_dex_decompiler.cc
@@ -0,0 +1,198 @@
+/*
+ * 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 "dex_to_dex_decompiler.h"
+
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
+#include "optimizing/bytecode_utils.h"
+
+namespace art {
+namespace optimizer {
+
+class DexDecompiler {
+ public:
+  DexDecompiler(const DexFile::CodeItem& code_item, const ArrayRef<const uint8_t>& quickened_info)
+    : code_item_(code_item),
+      quickened_info_ptr_(quickened_info.data()),
+      quickened_info_end_(quickened_info.data() + quickened_info.size()) {}
+
+  bool Decompile();
+
+ private:
+  void DecompileInstanceFieldAccess(Instruction* inst,
+                                    uint32_t dex_pc,
+                                    Instruction::Code new_opcode) {
+    uint16_t index = GetIndexAt(dex_pc);
+    inst->SetOpcode(new_opcode);
+    inst->SetVRegC_22c(index);
+  }
+
+  void DecompileInvokeVirtual(Instruction* inst,
+                              uint32_t dex_pc,
+                              Instruction::Code new_opcode,
+                              bool is_range) {
+    uint16_t index = GetIndexAt(dex_pc);
+    inst->SetOpcode(new_opcode);
+    if (is_range) {
+      inst->SetVRegB_3rc(index);
+    } else {
+      inst->SetVRegB_35c(index);
+    }
+  }
+
+  void DecompileNop(Instruction* inst, uint32_t dex_pc) {
+    if (quickened_info_ptr_ == quickened_info_end_) {
+      return;
+    }
+    const uint8_t* temporary_pointer = quickened_info_ptr_;
+    uint32_t quickened_pc = DecodeUnsignedLeb128(&temporary_pointer);
+    if (quickened_pc != dex_pc) {
+      return;
+    }
+    uint16_t reference_index = GetIndexAt(dex_pc);
+    uint16_t type_index = GetIndexAt(dex_pc);
+    inst->SetOpcode(Instruction::CHECK_CAST);
+    inst->SetVRegA_21c(reference_index);
+    inst->SetVRegB_21c(type_index);
+  }
+
+  uint16_t GetIndexAt(uint32_t dex_pc) {
+    // Note that as a side effect, DecodeUnsignedLeb128 update the given pointer
+    // to the new position in the buffer.
+    DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
+    uint32_t quickened_pc = DecodeUnsignedLeb128(&quickened_info_ptr_);
+    DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
+    uint16_t index = DecodeUnsignedLeb128(&quickened_info_ptr_);
+    DCHECK_LE(quickened_info_ptr_, quickened_info_end_);
+    DCHECK_EQ(quickened_pc, dex_pc);
+    return index;
+  }
+
+  const DexFile::CodeItem& code_item_;
+  const uint8_t* quickened_info_ptr_;
+  const uint8_t* const quickened_info_end_;
+
+  DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
+};
+
+bool DexDecompiler::Decompile() {
+  // We need to iterate over the code item, and not over the quickening data,
+  // because the RETURN_VOID quickening is not encoded in the quickening data. Because
+  // unquickening is a rare need and not performance sensitive, it is not worth the
+  // added storage to also add the RETURN_VOID quickening in the quickened data.
+  for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
+    uint32_t dex_pc = it.CurrentDexPc();
+    Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
+
+    switch (inst->Opcode()) {
+      case Instruction::RETURN_VOID_NO_BARRIER:
+        inst->SetOpcode(Instruction::RETURN_VOID);
+        break;
+
+      case Instruction::NOP:
+        DecompileNop(inst, dex_pc);
+        break;
+
+      case Instruction::IGET_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET);
+        break;
+
+      case Instruction::IGET_WIDE_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE);
+        break;
+
+      case Instruction::IGET_OBJECT_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT);
+        break;
+
+      case Instruction::IGET_BOOLEAN_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN);
+        break;
+
+      case Instruction::IGET_BYTE_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE);
+        break;
+
+      case Instruction::IGET_CHAR_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR);
+        break;
+
+      case Instruction::IGET_SHORT_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT);
+        break;
+
+      case Instruction::IPUT_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT);
+        break;
+
+      case Instruction::IPUT_BOOLEAN_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN);
+        break;
+
+      case Instruction::IPUT_BYTE_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE);
+        break;
+
+      case Instruction::IPUT_CHAR_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR);
+        break;
+
+      case Instruction::IPUT_SHORT_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT);
+        break;
+
+      case Instruction::IPUT_WIDE_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE);
+        break;
+
+      case Instruction::IPUT_OBJECT_QUICK:
+        DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT);
+        break;
+
+      case Instruction::INVOKE_VIRTUAL_QUICK:
+        DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL, false);
+        break;
+
+      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+        DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE, true);
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  if (quickened_info_ptr_ != quickened_info_end_) {
+    LOG(ERROR) << "Failed to use all values in quickening info."
+               << " Actual: " << std::hex << quickened_info_ptr_
+               << " Expected: " << quickened_info_end_;
+    return false;
+  }
+
+  return true;
+}
+
+bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
+                     const ArrayRef<const uint8_t>& quickened_info) {
+  DexDecompiler decompiler(code_item, quickened_info);
+  return decompiler.Decompile();
+}
+
+}  // namespace optimizer
+}  // namespace art
diff --git a/compiler/dex/dex_to_dex_decompiler.h b/compiler/dex/dex_to_dex_decompiler.h
new file mode 100644
index 0000000..5502ca2
--- /dev/null
+++ b/compiler/dex/dex_to_dex_decompiler.h
@@ -0,0 +1,38 @@
+/*
+ * 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_DEX_DEX_TO_DEX_DECOMPILER_H_
+#define ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
+
+#include "base/array_ref.h"
+#include "dex_file.h"
+
+namespace art {
+namespace optimizer {
+
+// "Decompile", that is unquicken, the code item provided, given the
+// associated quickening data.
+// TODO: code_item isn't really a const element, but changing it
+// to non-const has too many repercussions on the code base. We make it
+// consistent with DexToDexCompiler, but we should really change it to
+// DexFile::CodeItem*.
+bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
+                     const ArrayRef<const uint8_t>& quickened_data);
+
+}  // namespace optimizer
+}  // namespace art
+
+#endif  // ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
new file mode 100644
index 0000000..ea6c7a2
--- /dev/null
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -0,0 +1,136 @@
+/*
+ * 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 "dex/dex_to_dex_decompiler.h"
+
+#include "class_linker.h"
+#include "compiler/common_compiler_test.h"
+#include "compiler/compiled_method.h"
+#include "compiler/driver/compiler_options.h"
+#include "compiler/driver/compiler_driver.h"
+#include "compiler_callbacks.h"
+#include "dex_file.h"
+#include "handle_scope-inl.h"
+#include "verifier/method_verifier-inl.h"
+#include "mirror/class_loader.h"
+#include "runtime.h"
+#include "thread.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+class DexToDexDecompilerTest : public CommonCompilerTest {
+ public:
+  void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
+    TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
+    TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+    compiler_options_->boot_image_ = false;
+    compiler_options_->SetCompilerFilter(CompilerFilter::kInterpretOnly);
+    compiler_driver_->CompileAll(class_loader,
+                                 GetDexFiles(class_loader),
+                                 /* verifier_deps */ nullptr,
+                                 &timings);
+  }
+
+  void RunTest(const char* dex_name) {
+    Thread* self = Thread::Current();
+    // First load the original dex file.
+    jobject original_class_loader;
+    {
+      ScopedObjectAccess soa(self);
+      original_class_loader = LoadDex(dex_name);
+    }
+    const DexFile* original_dex_file = GetDexFiles(original_class_loader)[0];
+
+    // Load the dex file again and make it writable to quicken them.
+    jobject class_loader;
+    const DexFile* updated_dex_file = nullptr;
+    {
+      ScopedObjectAccess soa(self);
+      class_loader = LoadDex(dex_name);
+      updated_dex_file = GetDexFiles(class_loader)[0];
+      Runtime::Current()->GetClassLinker()->RegisterDexFile(
+          *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader).Ptr());
+    }
+    // The dex files should be identical.
+    int cmp = memcmp(original_dex_file->Begin(),
+                     updated_dex_file->Begin(),
+                     updated_dex_file->Size());
+    ASSERT_EQ(0, cmp);
+
+    updated_dex_file->EnableWrite();
+    CompileAll(class_loader);
+    // The dex files should be different after quickening.
+    cmp = memcmp(original_dex_file->Begin(), updated_dex_file->Begin(), updated_dex_file->Size());
+    ASSERT_NE(0, cmp);
+
+    // Unquicken the dex file.
+    for (uint32_t i = 0; i < updated_dex_file->NumClassDefs(); ++i) {
+      const DexFile::ClassDef& class_def = updated_dex_file->GetClassDef(i);
+      const uint8_t* class_data = updated_dex_file->GetClassData(class_def);
+      if (class_data == nullptr) {
+        continue;
+      }
+      ClassDataItemIterator it(*updated_dex_file, class_data);
+      // Skip fields
+      while (it.HasNextStaticField()) {
+        it.Next();
+      }
+      while (it.HasNextInstanceField()) {
+        it.Next();
+      }
+
+      // Unquicken each method.
+      while (it.HasNextDirectMethod()) {
+        uint32_t method_idx = it.GetMemberIndex();
+        CompiledMethod* compiled_method =
+            compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
+        ArrayRef<const uint8_t> table;
+        if (compiled_method != nullptr) {
+          table = compiled_method->GetVmapTable();
+        }
+        optimizer::ArtDecompileDEX(*it.GetMethodCodeItem(), table);
+        it.Next();
+      }
+      while (it.HasNextVirtualMethod()) {
+        uint32_t method_idx = it.GetMemberIndex();
+        CompiledMethod* compiled_method =
+            compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
+        ArrayRef<const uint8_t> table;
+        if (compiled_method != nullptr) {
+          table = compiled_method->GetVmapTable();
+        }
+        optimizer::ArtDecompileDEX(*it.GetMethodCodeItem(), table);
+        it.Next();
+      }
+      DCHECK(!it.HasNext());
+    }
+
+    // Make sure after unquickening we go back to the same contents as the original dex file.
+    cmp = memcmp(original_dex_file->Begin(), updated_dex_file->Begin(), updated_dex_file->Size());
+    ASSERT_EQ(0, cmp);
+  }
+};
+
+TEST_F(DexToDexDecompilerTest, VerifierDeps) {
+  RunTest("VerifierDeps");
+}
+
+TEST_F(DexToDexDecompilerTest, DexToDexDecompiler) {
+  RunTest("DexToDexDecompiler");
+}
+
+}  // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 223be88..aa0d10b 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -538,14 +538,9 @@
               : optimizer::DexToDexCompilationLevel::kRequired);
     }
   } else if ((access_flags & kAccNative) != 0) {
-    const InstructionSet instruction_set = driver->GetInstructionSet();
-    const bool use_generic_jni =
-        // Are we extracting only and have support for generic JNI down calls?
-        (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
-             InstructionSetHasGenericJniStub(instruction_set)) ||
-        // Always punt to generic JNI for MIPS because of no support for @CriticalNative. b/31743474
-        (instruction_set == kMips || instruction_set == kMips64);
-    if (use_generic_jni) {
+    // Are we extracting only and have support for generic JNI down calls?
+    if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
+        InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
       // Leaving this empty will trigger the generic JNI version
     } else {
       // Look-up the ArtMethod associated with this code_item (if any)
@@ -973,11 +968,12 @@
     return true;
   }
   DCHECK(profile_compilation_info_ != nullptr);
-  bool result = profile_compilation_info_->ContainsClass(dex_file, class_idx);
+  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_idx);
+  uint16_t type_idx = class_def.class_idx_;
+  bool result = profile_compilation_info_->ContainsClass(dex_file, type_idx);
   if (kDebugProfileGuidedCompilation) {
-    LOG(INFO) << "[ProfileGuidedCompilation] "
-        << (result ? "Verified" : "Skipped") << " method:"
-        << dex_file.GetClassDescriptor(dex_file.GetClassDef(class_idx));
+    LOG(INFO) << "[ProfileGuidedCompilation] " << (result ? "Verified" : "Skipped") << " method:"
+        << dex_file.GetClassDescriptor(class_def);
   }
   return result;
 }
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c8d6cb0..1bd3546 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -584,6 +584,7 @@
   const BitVector* current_dex_to_dex_methods_;
 
   friend class CompileClassVisitor;
+  friend class DexToDexDecompilerTest;
   friend class verifier::VerifierDepsTest;
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 56b632d..9c62f80 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -341,6 +341,7 @@
   const std::vector<std::string>* passes_to_run_;
 
   friend class Dex2Oat;
+  friend class DexToDexDecompilerTest;
   friend class CommonCompilerTest;
   friend class verifier::VerifierDepsTest;
 
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 31a7529..7c02384 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -879,7 +879,7 @@
     elf_header.e_ident[EI_MAG2]       = ELFMAG2;
     elf_header.e_ident[EI_MAG3]       = ELFMAG3;
     elf_header.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
-                                         ? ELFCLASS32 : ELFCLASS64;;
+                                         ? ELFCLASS32 : ELFCLASS64;
     elf_header.e_ident[EI_DATA]       = ELFDATA2LSB;
     elf_header.e_ident[EI_VERSION]    = EV_CURRENT;
     elf_header.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 51ef440..d7b7403 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -697,7 +697,7 @@
   return true;
 }
 
-class ComputeLazyFieldsForClassesVisitor : public ClassVisitor {
+class ImageWriter::ComputeLazyFieldsForClassesVisitor : public ClassVisitor {
  public:
   bool operator()(ObjPtr<Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     StackHandleScope<1> hs(Thread::Current());
@@ -837,7 +837,7 @@
   return true;
 }
 
-class NonImageClassesVisitor : public ClassVisitor {
+class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
  public:
   explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
 
@@ -1701,7 +1701,7 @@
   return reinterpret_cast<ArtMethod*>(image_info.image_begin_ + it->second.offset);
 }
 
-class FixupRootVisitor : public RootVisitor {
+class ImageWriter::FixupRootVisitor : public RootVisitor {
  public:
   explicit FixupRootVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {
   }
@@ -1944,7 +1944,7 @@
 }
 
 // Rewrite all the references in the copied object to point to their image address equivalent
-class FixupVisitor {
+class ImageWriter::FixupVisitor {
  public:
   FixupVisitor(ImageWriter* image_writer, Object* copy) : image_writer_(image_writer), copy_(copy) {
   }
@@ -1980,7 +1980,7 @@
   mirror::Object* const copy_;
 };
 
-class FixupClassVisitor FINAL : public FixupVisitor {
+class ImageWriter::FixupClassVisitor FINAL : public FixupVisitor {
  public:
   FixupClassVisitor(ImageWriter* image_writer, Object* copy) : FixupVisitor(image_writer, copy) {
   }
@@ -2045,7 +2045,7 @@
   }
 }
 
-class NativeLocationVisitor {
+class ImageWriter::NativeLocationVisitor {
  public:
   explicit NativeLocationVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
 
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index c9cf4cb..24fad46 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -582,14 +582,15 @@
   // Map of dex files to the indexes of oat files that they were compiled into.
   const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map_;
 
-  friend class ContainsBootClassLoaderNonImageClassVisitor;
-  friend class FixupClassVisitor;
-  friend class FixupRootVisitor;
-  friend class FixupVisitor;
+  class ComputeLazyFieldsForClassesVisitor;
+  class FixupClassVisitor;
+  class FixupRootVisitor;
+  class FixupVisitor;
   class GetRootsVisitor;
-  friend class NativeLocationVisitor;
-  friend class NonImageClassesVisitor;
+  class NativeLocationVisitor;
+  class NonImageClassesVisitor;
   class VisitReferencesVisitor;
+
   DISALLOW_COPY_AND_ASSIGN(ImageWriter);
 };
 
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index a9044a2..21042a3 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -20,6 +20,7 @@
 #include <math.h>
 
 #include "art_method-inl.h"
+#include "base/bit_utils.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
 #include "compiler.h"
@@ -366,7 +367,9 @@
   void StackArgsIntsFirstImpl();
   void StackArgsFloatsFirstImpl();
   void StackArgsMixedImpl();
+#if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
   void StackArgsSignExtendedMips64Impl();
+#endif
 
   void NormalNativeImpl();
   void FastNativeImpl();
@@ -2145,50 +2148,43 @@
 
 JNI_TEST_CRITICAL(StackArgsMixed)
 
-void Java_MyClassNatives_stackArgsSignExtendedMips64(JNIEnv*, jclass, jint i1, jint i2, jint i3,
-                                                     jint i4, jint i5, jint i6, jint i7, jint i8) {
-  EXPECT_EQ(i1, 1);
-  EXPECT_EQ(i2, 2);
-  EXPECT_EQ(i3, 3);
-  EXPECT_EQ(i4, 4);
-  EXPECT_EQ(i5, 5);
-  EXPECT_EQ(i6, 6);
-  EXPECT_EQ(i7, 7);
-  EXPECT_EQ(i8, -8);
-
 #if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-  // Mips64 ABI requires that arguments passed through stack be sign-extended 8B slots.
-  // First 8 arguments are passed through registers, check i7 and i8.
-  uint32_t stack1_high = *(&i7 + 1);
-  uint32_t stack2_high = *(&i8 + 1);
-
-  EXPECT_EQ(stack1_high, static_cast<uint32_t>(0));
-  EXPECT_EQ(stack2_high, static_cast<uint32_t>(0xffffffff));
-#else
-  LOG(INFO) << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
-            << kRuntimeISA;
-  // Force-print to std::cout so it's also outside the logcat.
-  std::cout << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
-            << kRuntimeISA << std::endl;
-#endif
+// Function will fetch the last argument passed from caller that is now on top of the stack and
+// return it as a 8B long. That way we can test if the caller has properly sign-extended the
+// value when placing it on the stack.
+__attribute__((naked))
+jlong Java_MyClassNatives_getStackArgSignExtendedMips64(
+    JNIEnv*, jclass,                      // Arguments passed from caller
+    jint, jint, jint, jint, jint, jint,   // through regs a0 to a7.
+    jint) {                               // The last argument will be passed on the stack.
+  __asm__(
+      ".set noreorder\n\t"                // Just return and store 8 bytes from the top of the stack
+      "jr  $ra\n\t"                       // in v0 (in branch delay slot). This should be the last
+      "ld  $v0, 0($sp)\n\t");             // argument. It is a 32-bit int, but it should be sign
+                                          // extended and it occupies 64-bit location.
 }
 
 void JniCompilerTest::StackArgsSignExtendedMips64Impl() {
-  SetUpForTest(true, "stackArgsSignExtendedMips64", "(IIIIIIII)V",
-               CURRENT_JNI_WRAPPER(Java_MyClassNatives_stackArgsSignExtendedMips64));
-  jint i1 = 1;
-  jint i2 = 2;
-  jint i3 = 3;
-  jint i4 = 4;
-  jint i5 = 5;
-  jint i6 = 6;
-  jint i7 = 7;
-  jint i8 = -8;
+  uint64_t ret;
+  SetUpForTest(true,
+               "getStackArgSignExtendedMips64",
+               "(IIIIIII)J",
+               // Don't use wrapper because this is raw assembly function.
+               reinterpret_cast<void*>(&Java_MyClassNatives_getStackArgSignExtendedMips64));
 
-  env_->CallStaticVoidMethod(jklass_, jmethod_, i1, i2, i3, i4, i5, i6, i7, i8);
+  // Mips64 ABI requires that arguments passed through stack be sign-extended 8B slots.
+  // First 8 arguments are passed through registers.
+  // Final argument's value is 7. When sign-extended, higher stack bits should be 0.
+  ret = env_->CallStaticLongMethod(jklass_, jmethod_, 1, 2, 3, 4, 5, 6, 7);
+  EXPECT_EQ(High32Bits(ret), static_cast<uint32_t>(0));
+
+  // Final argument's value is -8.  When sign-extended, higher stack bits should be 0xffffffff.
+  ret = env_->CallStaticLongMethod(jklass_, jmethod_, 1, 2, 3, 4, 5, 6, -8);
+  EXPECT_EQ(High32Bits(ret), static_cast<uint32_t>(0xffffffff));
 }
 
-JNI_TEST_CRITICAL(StackArgsSignExtendedMips64)
+JNI_TEST(StackArgsSignExtendedMips64)
+#endif
 
 void Java_MyClassNatives_normalNative(JNIEnv*, jclass) {
   // Intentionally left empty.
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 3fb7b56..33f4d77 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -222,7 +222,11 @@
                                                      bool is_synchronized,
                                                      bool is_critical_native,
                                                      const char* shorty)
-    : JniCallingConvention(is_static, is_synchronized, is_critical_native, shorty, kArm64PointerSize) {
+    : JniCallingConvention(is_static,
+                           is_synchronized,
+                           is_critical_native,
+                           shorty,
+                           kArm64PointerSize) {
 }
 
 uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index 9859b5d..36a87a8 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -152,24 +152,6 @@
                                                                    bool is_critical_native,
                                                                    const char* shorty,
                                                                    InstructionSet instruction_set) {
-  if (UNLIKELY(is_critical_native)) {
-    // Sanity check that the requested JNI instruction set
-    // is supported for critical natives. Not every one is.
-    switch (instruction_set) {
-      case kX86_64:
-      case kX86:
-      case kArm64:
-      case kArm:
-      case kThumb2:
-        break;
-      default:
-        is_critical_native = false;
-        LOG(WARNING) << "@CriticalNative support not implemented for " << instruction_set
-                     << "; will crash at runtime if trying to invoke such a method.";
-        // TODO: implement for MIPS/MIPS64
-    }
-  }
-
   switch (instruction_set) {
 #ifdef ART_ENABLE_CODEGEN_arm
     case kArm:
@@ -191,12 +173,18 @@
 #ifdef ART_ENABLE_CODEGEN_mips
     case kMips:
       return std::unique_ptr<JniCallingConvention>(
-          new (arena) mips::MipsJniCallingConvention(is_static, is_synchronized, shorty));
+          new (arena) mips::MipsJniCallingConvention(is_static,
+                                                     is_synchronized,
+                                                     is_critical_native,
+                                                     shorty));
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips64
     case kMips64:
       return std::unique_ptr<JniCallingConvention>(
-          new (arena) mips64::Mips64JniCallingConvention(is_static, is_synchronized, shorty));
+          new (arena) mips64::Mips64JniCallingConvention(is_static,
+                                                         is_synchronized,
+                                                         is_critical_native,
+                                                         shorty));
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86
     case kX86:
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index f541d8f..335a2df 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -370,14 +370,6 @@
     kObjectOrClass = 1
   };
 
-  // TODO: remove this constructor once all are changed to the below one.
-  JniCallingConvention(bool is_static,
-                       bool is_synchronized,
-                       const char* shorty,
-                       PointerSize frame_pointer_size)
-      : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size),
-        is_critical_native_(false) {}
-
   JniCallingConvention(bool is_static,
                        bool is_synchronized,
                        bool is_critical_native,
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index f5ab5f7..e6948ec 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -23,6 +23,13 @@
 namespace art {
 namespace mips {
 
+// Up to how many float-like (float, double) args can be enregistered in floating-point registers.
+// The rest of the args must go in integer registers or on the stack.
+constexpr size_t kMaxFloatOrDoubleRegisterArguments = 2u;
+// Up to how many integer-like (pointers, objects, longs, int, short, bool, etc) args can be
+// enregistered. The rest of the args must go on the stack.
+constexpr size_t kMaxIntLikeRegisterArguments = 4u;
+
 static const Register kCoreArgumentRegisters[] = { A0, A1, A2, A3 };
 static const FRegister kFArgumentRegisters[] = { F12, F14 };
 static const DRegister kDArgumentRegisters[] = { D6, D7 };
@@ -170,23 +177,134 @@
 }
 // JNI calling convention
 
-MipsJniCallingConvention::MipsJniCallingConvention(bool is_static, bool is_synchronized,
+MipsJniCallingConvention::MipsJniCallingConvention(bool is_static,
+                                                   bool is_synchronized,
+                                                   bool is_critical_native,
                                                    const char* shorty)
-    : JniCallingConvention(is_static, is_synchronized, shorty, kMipsPointerSize) {
-  // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
-  // or jclass for static methods and the JNIEnv. We start at the aligned register A2.
+    : JniCallingConvention(is_static,
+                           is_synchronized,
+                           is_critical_native,
+                           shorty,
+                           kMipsPointerSize) {
+  // SYSTEM V - Application Binary Interface (MIPS RISC Processor):
+  // Data Representation - Fundamental Types (3-4) specifies fundamental alignments for each type.
+  //   "Each member is assigned to the lowest available offset with the appropriate alignment. This
+  // may require internal padding, depending on the previous member."
+  //
+  // All of our stack arguments are usually 4-byte aligned, however longs and doubles must be 8
+  // bytes aligned. Add padding to maintain 8-byte alignment invariant.
+  //
+  // Compute padding to ensure longs and doubles are not split in o32.
   size_t padding = 0;
-  for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
+  size_t cur_arg, cur_reg;
+  if (LIKELY(HasExtraArgumentsForJni())) {
+    // Ignore the 'this' jobject or jclass for static methods and the JNIEnv.
+    // We start at the aligned register A2.
+    //
+    // Ignore the first 2 parameters because they are guaranteed to be aligned.
+    cur_arg = NumImplicitArgs();  // Skip the "this" argument.
+    cur_reg = 2;  // Skip {A0=JNIEnv, A1=jobject} / {A0=JNIEnv, A1=jclass} parameters (start at A2).
+  } else {
+    // Check every parameter.
+    cur_arg = 0;
+    cur_reg = 0;
+  }
+
+  // Shift across a logical register mapping that looks like:
+  //
+  //   | A0 | A1 | A2 | A3 | SP+16 | SP+20 | SP+24 | ... | SP+n | SP+n+4 |
+  //
+  //   or some of variants with floating-point registers (F12 and F14), for example
+  //
+  //   | F12     | F14 | A3 | SP+16 | SP+20 | SP+24 | ... | SP+n | SP+n+4 |
+  //
+  //   (where SP is the stack pointer at the start of called function).
+  //
+  // Any time there would normally be a long/double in an odd logical register,
+  // we have to push out the rest of the mappings by 4 bytes to maintain an 8-byte alignment.
+  //
+  // This works for both physical register pairs {A0, A1}, {A2, A3},
+  // floating-point registers F12, F14 and for when the value is on the stack.
+  //
+  // For example:
+  // (a) long would normally go into A1, but we shift it into A2
+  //  | INT | (PAD) | LONG    |
+  //  | A0  |  A1   | A2 | A3 |
+  //
+  // (b) long would normally go into A3, but we shift it into SP
+  //  | INT | INT | INT | (PAD) | LONG        |
+  //  | A0  | A1  | A2  |  A3   | SP+16 SP+20 |
+  //
+  // where INT is any <=4 byte arg, and LONG is any 8-byte arg.
+  for (; cur_arg < NumArgs(); cur_arg++) {
     if (IsParamALongOrDouble(cur_arg)) {
       if ((cur_reg & 1) != 0) {
         padding += 4;
-        cur_reg++;  // additional bump to ensure alignment
+        cur_reg++;   // Additional bump to ensure alignment.
       }
-      cur_reg++;  // additional bump to skip extra long word
+      cur_reg += 2;  // Bump the iterator twice for every long argument.
+    } else {
+      cur_reg++;     // Bump the iterator for every argument.
     }
-    cur_reg++;  // bump the iterator for every argument
   }
-  padding_ = padding;
+  if (cur_reg < kMaxIntLikeRegisterArguments) {
+    // As a special case when, as a result of shifting (or not) there are no arguments on the stack,
+    // we actually have 0 stack padding.
+    //
+    // For example with @CriticalNative and:
+    // (int, long) -> shifts the long but doesn't need to pad the stack
+    //
+    //          shift
+    //           \/
+    //  | INT | (PAD) | LONG      | (EMPTY) ...
+    //  | r0  |  r1   |  r2  | r3 |   SP    ...
+    //                                /\
+    //                          no stack padding
+    padding_ = 0;
+  } else {
+    padding_ = padding;
+  }
+
+  // Argument Passing (3-17):
+  //   "When the first argument is integral, the remaining arguments are passed in the integer
+  // registers."
+  //
+  //   "The rules that determine which arguments go into registers and which ones must be passed on
+  // the stack are most easily explained by considering the list of arguments as a structure,
+  // aligned according to normal structure rules. Mapping of this structure into the combination of
+  // stack and registers is as follows: up to two leading floating-point arguments can be passed in
+  // $f12 and $f14; everything else with a structure offset greater than or equal to 16 is passed on
+  // the stack. The remainder of the arguments are passed in $4..$7 based on their structure offset.
+  // Holes left in the structure for alignment are unused, whether in registers or in the stack."
+  //
+  // For example with @CriticalNative and:
+  // (a) first argument is not floating-point, so all go into integer registers
+  //  | INT | FLOAT | DOUBLE  |
+  //  | A0  |  A1   | A2 | A3 |
+  // (b) first argument is floating-point, but 2nd is integer
+  //  | FLOAT | INT | DOUBLE  |
+  //  |  F12  | A1  | A2 | A3 |
+  // (c) first two arguments are floating-point (float, double)
+  //  | FLAOT | (PAD) | DOUBLE |  INT  |
+  //  |  F12  |       |  F14   | SP+16 |
+  // (d) first two arguments are floating-point (double, float)
+  //  | DOUBLE | FLOAT | INT |
+  //  |  F12   |  F14  | A3  |
+  // (e) first three arguments are floating-point, but just first two will go into fp registers
+  //  | DOUBLE | FLOAT | FLOAT |
+  //  |  F12   |  F14  |  A3   |
+  //
+  // Find out if the first argument is a floating-point. In that case, floating-point registers will
+  // be used for up to two leading floating-point arguments. Otherwise, all arguments will be passed
+  // using integer registers.
+  use_fp_arg_registers_ = false;
+  if (is_critical_native) {
+    if (NumArgs() > 0) {
+      if (IsParamAFloatOrDouble(0)) {
+        use_fp_arg_registers_ = true;
+      }
+    }
+  }
 }
 
 uint32_t MipsJniCallingConvention::CoreSpillMask() const {
@@ -202,74 +320,127 @@
 }
 
 size_t MipsJniCallingConvention::FrameSize() {
-  // ArtMethod*, RA and callee save area size, local reference segment state
-  size_t frame_data_size = static_cast<size_t>(kMipsPointerSize) +
-      (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
-  // References plus 2 words for HandleScope header
-  size_t handle_scope_size = HandleScope::SizeOf(kMipsPointerSize, ReferenceCount());
-  // Plus return value spill area size
-  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
+  // ArtMethod*, RA and callee save area size, local reference segment state.
+  const size_t method_ptr_size = static_cast<size_t>(kMipsPointerSize);
+  const size_t ra_return_addr_size = kFramePointerSize;
+  const size_t callee_save_area_size = CalleeSaveRegisters().size() * kFramePointerSize;
+
+  size_t frame_data_size = method_ptr_size + ra_return_addr_size + callee_save_area_size;
+
+  if (LIKELY(HasLocalReferenceSegmentState())) {
+    // Local reference segment state.
+    frame_data_size += kFramePointerSize;
+  }
+
+  // References plus 2 words for HandleScope header.
+  const size_t handle_scope_size = HandleScope::SizeOf(kMipsPointerSize, ReferenceCount());
+
+  size_t total_size = frame_data_size;
+  if (LIKELY(HasHandleScope())) {
+    // HandleScope is sometimes excluded.
+    total_size += handle_scope_size;    // Handle scope size.
+  }
+
+  // Plus return value spill area size.
+  total_size += SizeOfReturnValue();
+
+  return RoundUp(total_size, kStackAlignment);
 }
 
 size_t MipsJniCallingConvention::OutArgSize() {
-  return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_, kStackAlignment);
+  // Argument Passing (3-17):
+  //   "Despite the fact that some or all of the arguments to a function are passed in registers,
+  // always allocate space on the stack for all arguments. This stack space should be a structure
+  // large enough to contain all the arguments, aligned according to normal structure rules (after
+  // promotion and structure return pointer insertion). The locations within the stack frame used
+  // for arguments are called the home locations."
+  //
+  // Allocate 16 bytes for home locations + space needed for stack arguments.
+  return RoundUp(
+      (kMaxIntLikeRegisterArguments + NumberOfOutgoingStackArgs()) * kFramePointerSize + padding_,
+      kStackAlignment);
 }
 
 ArrayRef<const ManagedRegister> MipsJniCallingConvention::CalleeSaveRegisters() const {
   return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
 }
 
-// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
-// in even register numbers and stack slots
+// JniCallingConvention ABI follows o32 where longs and doubles must occur
+// in even register numbers and stack slots.
 void MipsJniCallingConvention::Next() {
   JniCallingConvention::Next();
-  size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
-  if ((itr_args_ >= 2) &&
-      (arg_pos < NumArgs()) &&
-      IsParamALongOrDouble(arg_pos)) {
-    // itr_slots_ needs to be an even number, according to AAPCS.
-    if ((itr_slots_ & 0x1u) != 0) {
+
+  if (LIKELY(HasNext())) {  // Avoid CHECK failure for IsCurrentParam
+    // Ensure slot is 8-byte aligned for longs/doubles (o32).
+    if (IsCurrentParamALongOrDouble() && ((itr_slots_ & 0x1u) != 0)) {
+      // itr_slots_ needs to be an even number, according to o32.
       itr_slots_++;
     }
   }
 }
 
 bool MipsJniCallingConvention::IsCurrentParamInRegister() {
-  return itr_slots_ < 4;
+  // Argument Passing (3-17):
+  //   "The rules that determine which arguments go into registers and which ones must be passed on
+  // the stack are most easily explained by considering the list of arguments as a structure,
+  // aligned according to normal structure rules. Mapping of this structure into the combination of
+  // stack and registers is as follows: up to two leading floating-point arguments can be passed in
+  // $f12 and $f14; everything else with a structure offset greater than or equal to 16 is passed on
+  // the stack. The remainder of the arguments are passed in $4..$7 based on their structure offset.
+  // Holes left in the structure for alignment are unused, whether in registers or in the stack."
+  //
+  // Even when floating-point registers are used, there can be up to 4 arguments passed in
+  // registers.
+  return itr_slots_ < kMaxIntLikeRegisterArguments;
 }
 
 bool MipsJniCallingConvention::IsCurrentParamOnStack() {
   return !IsCurrentParamInRegister();
 }
 
-static const Register kJniArgumentRegisters[] = {
-  A0, A1, A2, A3
-};
 ManagedRegister MipsJniCallingConvention::CurrentParamRegister() {
-  CHECK_LT(itr_slots_, 4u);
-  int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
-  if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
-    CHECK_EQ(itr_slots_, 2u);
-    return MipsManagedRegister::FromRegisterPair(A2_A3);
+  CHECK_LT(itr_slots_, kMaxIntLikeRegisterArguments);
+  // Up to two leading floating-point arguments can be passed in floating-point registers.
+  if (use_fp_arg_registers_ && (itr_args_ < kMaxFloatOrDoubleRegisterArguments)) {
+    if (IsCurrentParamAFloatOrDouble()) {
+      if (IsCurrentParamADouble()) {
+        return MipsManagedRegister::FromDRegister(kDArgumentRegisters[itr_args_]);
+      } else {
+        return MipsManagedRegister::FromFRegister(kFArgumentRegisters[itr_args_]);
+      }
+    }
+  }
+  // All other arguments (including other floating-point arguments) will be passed in integer
+  // registers.
+  if (IsCurrentParamALongOrDouble()) {
+    if (itr_slots_ == 0u) {
+      return MipsManagedRegister::FromRegisterPair(A0_A1);
+    } else {
+      CHECK_EQ(itr_slots_, 2u);
+      return MipsManagedRegister::FromRegisterPair(A2_A3);
+    }
   } else {
-    return
-      MipsManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
+    return MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[itr_slots_]);
   }
 }
 
 FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
-  CHECK_GE(itr_slots_, 4u);
+  CHECK_GE(itr_slots_, kMaxIntLikeRegisterArguments);
   size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize);
   CHECK_LT(offset, OutArgSize());
   return FrameOffset(offset);
 }
 
 size_t MipsJniCallingConvention::NumberOfOutgoingStackArgs() {
-  size_t static_args = IsStatic() ? 1 : 0;  // count jclass
-  // regular argument parameters and this
-  size_t param_args = NumArgs() + NumLongOrDoubleArgs();
-  // count JNIEnv*
-  return static_args + param_args + 1;
+  size_t static_args = HasSelfClass() ? 1 : 0;            // Count jclass.
+  // Regular argument parameters and this.
+  size_t param_args = NumArgs() + NumLongOrDoubleArgs();  // Twice count 8-byte args.
+  // Count JNIEnv* less arguments in registers.
+  size_t internal_args = (HasJniEnv() ? 1 : 0);
+  size_t total_args = static_args + param_args + internal_args;
+
+  return total_args - std::min(kMaxIntLikeRegisterArguments, static_cast<size_t>(total_args));
 }
+
 }  // namespace mips
 }  // namespace art
diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h
index e95a738..ad3f118 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.h
+++ b/compiler/jni/quick/mips/calling_convention_mips.h
@@ -54,14 +54,17 @@
 
 class MipsJniCallingConvention FINAL : public JniCallingConvention {
  public:
-  MipsJniCallingConvention(bool is_static, bool is_synchronized, const char* shorty);
+  MipsJniCallingConvention(bool is_static,
+                           bool is_synchronized,
+                           bool is_critical_native,
+                           const char* shorty);
   ~MipsJniCallingConvention() OVERRIDE {}
   // Calling convention
   ManagedRegister ReturnRegister() OVERRIDE;
   ManagedRegister IntReturnRegister() OVERRIDE;
   ManagedRegister InterproceduralScratchRegister() OVERRIDE;
   // JNI calling convention
-  void Next() OVERRIDE;  // Override default behavior for AAPCS
+  void Next() OVERRIDE;  // Override default behavior for o32.
   size_t FrameSize() OVERRIDE;
   size_t OutArgSize() OVERRIDE;
   ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
@@ -82,8 +85,9 @@
   size_t NumberOfOutgoingStackArgs() OVERRIDE;
 
  private:
-  // Padding to ensure longs and doubles are not split in AAPCS
+  // Padding to ensure longs and doubles are not split in o32.
   size_t padding_;
+  size_t use_fp_arg_registers_;
 
   DISALLOW_COPY_AND_ASSIGN(MipsJniCallingConvention);
 };
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc
index 8341e8e..afe6a76 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.cc
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc
@@ -23,6 +23,9 @@
 namespace art {
 namespace mips64 {
 
+// Up to kow many args can be enregistered. The rest of the args must go on the stack.
+constexpr size_t kMaxRegisterArguments = 8u;
+
 static const GpuRegister kGpuArgumentRegisters[] = {
   A0, A1, A2, A3, A4, A5, A6, A7
 };
@@ -150,9 +153,15 @@
 
 // JNI calling convention
 
-Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, bool is_synchronized,
+Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static,
+                                                       bool is_synchronized,
+                                                       bool is_critical_native,
                                                        const char* shorty)
-    : JniCallingConvention(is_static, is_synchronized, shorty, kMips64PointerSize) {
+    : JniCallingConvention(is_static,
+                           is_synchronized,
+                           is_critical_native,
+                           shorty,
+                           kMips64PointerSize) {
 }
 
 uint32_t Mips64JniCallingConvention::CoreSpillMask() const {
@@ -168,13 +177,28 @@
 }
 
 size_t Mips64JniCallingConvention::FrameSize() {
-  // ArtMethod*, RA and callee save area size, local reference segment state
-  size_t frame_data_size = kFramePointerSize +
-      (CalleeSaveRegisters().size() + 1) * kFramePointerSize + sizeof(uint32_t);
-  // References plus 2 words for HandleScope header
+  // ArtMethod*, RA and callee save area size, local reference segment state.
+  size_t method_ptr_size = static_cast<size_t>(kFramePointerSize);
+  size_t ra_and_callee_save_area_size = (CalleeSaveRegisters().size() + 1) * kFramePointerSize;
+
+  size_t frame_data_size = method_ptr_size + ra_and_callee_save_area_size;
+  if (LIKELY(HasLocalReferenceSegmentState())) {                     // Local ref. segment state.
+    // Local reference segment state is sometimes excluded.
+    frame_data_size += sizeof(uint32_t);
+  }
+  // References plus 2 words for HandleScope header.
   size_t handle_scope_size = HandleScope::SizeOf(kMips64PointerSize, ReferenceCount());
-  // Plus return value spill area size
-  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
+
+  size_t total_size = frame_data_size;
+  if (LIKELY(HasHandleScope())) {
+    // HandleScope is sometimes excluded.
+    total_size += handle_scope_size;                                 // Handle scope size.
+  }
+
+  // Plus return value spill area size.
+  total_size += SizeOfReturnValue();
+
+  return RoundUp(total_size, kStackAlignment);
 }
 
 size_t Mips64JniCallingConvention::OutArgSize() {
@@ -186,7 +210,7 @@
 }
 
 bool Mips64JniCallingConvention::IsCurrentParamInRegister() {
-  return itr_args_ < 8;
+  return itr_args_ < kMaxRegisterArguments;
 }
 
 bool Mips64JniCallingConvention::IsCurrentParamOnStack() {
@@ -204,7 +228,8 @@
 
 FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() {
   CHECK(IsCurrentParamOnStack());
-  size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_args_ - 8) * kFramePointerSize);
+  size_t args_on_stack = itr_args_ - kMaxRegisterArguments;
+  size_t offset = displacement_.Int32Value() - OutArgSize() + (args_on_stack * kFramePointerSize);
   CHECK_LT(offset, OutArgSize());
   return FrameOffset(offset);
 }
@@ -214,7 +239,7 @@
   size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni();
 
   // Nothing on the stack unless there are more than 8 arguments
-  return (all_args > 8) ? all_args - 8 : 0;
+  return (all_args > kMaxRegisterArguments) ? all_args - kMaxRegisterArguments : 0;
 }
 }  // namespace mips64
 }  // namespace art
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.h b/compiler/jni/quick/mips64/calling_convention_mips64.h
index a5fd111..faedaef 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.h
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.h
@@ -54,7 +54,10 @@
 
 class Mips64JniCallingConvention FINAL : public JniCallingConvention {
  public:
-  Mips64JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty);
+  Mips64JniCallingConvention(bool is_static,
+                             bool is_synchronized,
+                             bool is_critical_native,
+                             const char* shorty);
   ~Mips64JniCallingConvention() OVERRIDE {}
   // Calling convention
   ManagedRegister ReturnRegister() OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 9725a16..a341086 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6497,12 +6497,9 @@
                                         iftable_offset,
                                         maybe_temp2_loc,
                                         kWithoutReadBarrier);
-      // Null iftable means it is empty and will always fail the check.
-      __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
-
-      // Loop through the iftable and check if any class matches.
+      // Iftable is never null.
       __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
-
+      // Loop through the iftable and check if any class matches.
       Label start_loop;
       __ Bind(&start_loop);
       __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 2b575f7..c9e563b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3804,12 +3804,9 @@
                                         iftable_offset,
                                         maybe_temp2_loc,
                                         kWithoutReadBarrier);
-      // Null iftable means it is empty and will always fail the check.
-      __ Cbz(temp, type_check_slow_path->GetEntryLabel());
-
-      // Loop through the iftable and check if any class matches.
+      // Iftable is never null.
       __ Ldr(WRegisterFrom(maybe_temp2_loc), HeapOperand(temp.W(), array_length_offset));
-
+      // Loop through the iftable and check if any class matches.
       vixl::aarch64::Label start_loop;
       __ Bind(&start_loop);
       __ Cbz(WRegisterFrom(maybe_temp2_loc), type_check_slow_path->GetEntryLabel());
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index e9827e8..61e6b4b 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -680,6 +680,15 @@
                              CodeBufferCheckScope::kMaximumSize);
   // TODO(VIXL): Check that using lower case bind is fine here.
   codegen->GetVIXLAssembler()->bind(&table_start_);
+  for (uint32_t i = 0; i < num_entries; i++) {
+    codegen->GetVIXLAssembler()->place(bb_addresses_[i].get());
+  }
+}
+
+void JumpTableARMVIXL::FixTable(CodeGeneratorARMVIXL* codegen) {
+  uint32_t num_entries = switch_instr_->GetNumEntries();
+  DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold);
+
   const ArenaVector<HBasicBlock*>& successors = switch_instr_->GetBlock()->GetSuccessors();
   for (uint32_t i = 0; i < num_entries; i++) {
     vixl32::Label* target_label = codegen->GetLabelOf(successors[i]);
@@ -691,21 +700,21 @@
     }
     DCHECK_GT(jump_offset, std::numeric_limits<int32_t>::min());
     DCHECK_LE(jump_offset, std::numeric_limits<int32_t>::max());
-    vixl32::Literal<int32_t> literal(jump_offset);
-    codegen->GetVIXLAssembler()->place(&literal);
+
+    bb_addresses_[i].get()->UpdateValue(jump_offset, &codegen->GetVIXLAssembler()->GetBuffer());
   }
 }
 
-void CodeGeneratorARMVIXL::EmitJumpTables() {
+void CodeGeneratorARMVIXL::FixJumpTables() {
   for (auto&& jump_table : jump_tables_) {
-    jump_table->EmitTable(this);
+    jump_table->FixTable(this);
   }
 }
 
 #define __ reinterpret_cast<ArmVIXLAssembler*>(GetAssembler())->GetVIXLAssembler()->  // NOLINT
 
 void CodeGeneratorARMVIXL::Finalize(CodeAllocator* allocator) {
-  EmitJumpTables();
+  FixJumpTables();
   GetAssembler()->FinalizeCode();
   CodeGenerator::Finalize(allocator);
 }
@@ -2016,7 +2025,7 @@
         case Primitive::kPrimFloat: {
           // Processing a Dex `float-to-int' instruction.
           vixl32::SRegister temp = LowSRegisterFrom(locations->GetTemp(0));
-          __ Vcvt(I32, F32, temp, InputSRegisterAt(conversion, 0));
+          __ Vcvt(S32, F32, temp, InputSRegisterAt(conversion, 0));
           __ Vmov(OutputRegister(conversion), temp);
           break;
         }
@@ -2024,7 +2033,7 @@
         case Primitive::kPrimDouble: {
           // Processing a Dex `double-to-int' instruction.
           vixl32::SRegister temp_s = LowSRegisterFrom(locations->GetTemp(0));
-          __ Vcvt(I32, F64, temp_s, DRegisterFrom(in));
+          __ Vcvt(S32, F64, temp_s, DRegisterFrom(in));
           __ Vmov(OutputRegister(conversion), temp_s);
           break;
         }
@@ -2100,7 +2109,7 @@
         case Primitive::kPrimChar: {
           // Processing a Dex `int-to-float' instruction.
           __ Vmov(OutputSRegister(conversion), InputRegisterAt(conversion, 0));
-          __ Vcvt(F32, I32, OutputSRegister(conversion), OutputSRegister(conversion));
+          __ Vcvt(F32, S32, OutputSRegister(conversion), OutputSRegister(conversion));
           break;
         }
 
@@ -2131,7 +2140,7 @@
         case Primitive::kPrimChar: {
           // Processing a Dex `int-to-double' instruction.
           __ Vmov(LowSRegisterFrom(out), InputRegisterAt(conversion, 0));
-          __ Vcvt(F64, I32, DRegisterFrom(out), LowSRegisterFrom(out));
+          __ Vcvt(F64, S32, DRegisterFrom(out), LowSRegisterFrom(out));
           break;
         }
 
@@ -2139,18 +2148,15 @@
           // Processing a Dex `long-to-double' instruction.
           vixl32::Register low = LowRegisterFrom(in);
           vixl32::Register high = HighRegisterFrom(in);
-
           vixl32::SRegister out_s = LowSRegisterFrom(out);
           vixl32::DRegister out_d = DRegisterFrom(out);
-
           vixl32::SRegister temp_s = LowSRegisterFrom(locations->GetTemp(0));
           vixl32::DRegister temp_d = DRegisterFrom(locations->GetTemp(0));
-
-          vixl32::DRegister constant_d = DRegisterFrom(locations->GetTemp(0));
+          vixl32::DRegister constant_d = DRegisterFrom(locations->GetTemp(1));
 
           // temp_d = int-to-double(high)
           __ Vmov(temp_s, high);
-          __ Vcvt(F64, I32, temp_d, temp_s);
+          __ Vcvt(F64, S32, temp_d, temp_s);
           // constant_d = k2Pow32EncodingForDouble
           __ Vmov(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
           // out_d = unsigned-to-double(low)
@@ -4164,7 +4170,14 @@
         vixl32::Register temp = temps.Acquire();
 
         if (has_intermediate_address) {
-          TODO_VIXL32(FATAL);
+          // We do not need to compute the intermediate address from the array: the
+          // input instruction has done it already. See the comment in
+          // `TryExtractArrayAccessAddress()`.
+          if (kIsDebugBuild) {
+            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
+            DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+          }
+          temp = obj;
         } else {
           __ Add(temp, obj, data_offset);
         }
@@ -4209,7 +4222,14 @@
           vixl32::Register temp = temps.Acquire();
 
           if (has_intermediate_address) {
-            TODO_VIXL32(FATAL);
+            // We do not need to compute the intermediate address from the array: the
+            // input instruction has done it already. See the comment in
+            // `TryExtractArrayAccessAddress()`.
+            if (kIsDebugBuild) {
+              HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
+              DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+            }
+            temp = obj;
           } else {
             __ Add(temp, obj, data_offset);
           }
@@ -4337,7 +4357,14 @@
         vixl32::Register temp = temps.Acquire();
 
         if (has_intermediate_address) {
-          TODO_VIXL32(FATAL);
+          // We do not need to compute the intermediate address from the array: the
+          // input instruction has done it already. See the comment in
+          // `TryExtractArrayAccessAddress()`.
+          if (kIsDebugBuild) {
+            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
+            DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
+          }
+          temp = array;
         } else {
           __ Add(temp, array, data_offset);
         }
@@ -4556,6 +4583,32 @@
   }
 }
 
+void LocationsBuilderARMVIXL::VisitIntermediateAddress(HIntermediateAddress* instruction) {
+  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
+  DCHECK(!kEmitCompilerReadBarrier);
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitIntermediateAddress(HIntermediateAddress* instruction) {
+  vixl32::Register out = OutputRegister(instruction);
+  vixl32::Register first = InputRegisterAt(instruction, 0);
+  Location second = instruction->GetLocations()->InAt(1);
+
+  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
+  DCHECK(!kEmitCompilerReadBarrier);
+
+  if (second.IsRegister()) {
+    __ Add(out, first, RegisterFrom(second));
+  } else {
+    __ Add(out, first, second.GetConstant()->AsIntConstant()->GetValue());
+  }
+}
+
 void LocationsBuilderARMVIXL::VisitBoundsCheck(HBoundsCheck* instruction) {
   RegisterSet caller_saves = RegisterSet::Empty();
   InvokeRuntimeCallingConventionARMVIXL calling_convention;
@@ -5156,11 +5209,14 @@
     __ Cbz(obj, &zero);
   }
 
-  // /* HeapReference<Class> */ out = obj->klass_
-  GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
-
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck: {
+      // /* HeapReference<Class> */ out = obj->klass_
+      GenerateReferenceLoadTwoRegisters(instruction,
+                                        out_loc,
+                                        obj_loc,
+                                        class_offset,
+                                        maybe_temp_loc);
       __ Cmp(out, cls);
       // Classes must be equal for the instanceof to succeed.
       __ B(ne, &zero);
@@ -5170,6 +5226,12 @@
     }
 
     case TypeCheckKind::kAbstractClassCheck: {
+      // /* HeapReference<Class> */ out = obj->klass_
+      GenerateReferenceLoadTwoRegisters(instruction,
+                                        out_loc,
+                                        obj_loc,
+                                        class_offset,
+                                        maybe_temp_loc);
       // If the class is abstract, we eagerly fetch the super class of the
       // object to avoid doing a comparison we know will fail.
       vixl32::Label loop;
@@ -5188,6 +5250,12 @@
     }
 
     case TypeCheckKind::kClassHierarchyCheck: {
+      // /* HeapReference<Class> */ out = obj->klass_
+      GenerateReferenceLoadTwoRegisters(instruction,
+                                        out_loc,
+                                        obj_loc,
+                                        class_offset,
+                                        maybe_temp_loc);
       // Walk over the class hierarchy to find a match.
       vixl32::Label loop, success;
       __ Bind(&loop);
@@ -5207,6 +5275,12 @@
     }
 
     case TypeCheckKind::kArrayObjectCheck: {
+      // /* HeapReference<Class> */ out = obj->klass_
+      GenerateReferenceLoadTwoRegisters(instruction,
+                                        out_loc,
+                                        obj_loc,
+                                        class_offset,
+                                        maybe_temp_loc);
       // Do an exact check.
       vixl32::Label exact_check;
       __ Cmp(out, cls);
@@ -5226,6 +5300,12 @@
     }
 
     case TypeCheckKind::kArrayCheck: {
+      // /* HeapReference<Class> */ out = obj->klass_
+      GenerateReferenceLoadTwoRegisters(instruction,
+                                        out_loc,
+                                        obj_loc,
+                                        class_offset,
+                                        maybe_temp_loc);
       __ Cmp(out, cls);
       DCHECK(locations->OnlyCallsOnSlowPath());
       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARMVIXL(instruction,
@@ -5491,6 +5571,70 @@
   HandleBitwiseOperation(instruction);
 }
 
+void LocationsBuilderARMVIXL::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  Location out = locations->Out();
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    vixl32::Register first_reg = RegisterFrom(first);
+    vixl32::Register second_reg = RegisterFrom(second);
+    vixl32::Register out_reg = RegisterFrom(out);
+
+    switch (instruction->GetOpKind()) {
+      case HInstruction::kAnd:
+        __ Bic(out_reg, first_reg, second_reg);
+        break;
+      case HInstruction::kOr:
+        __ Orn(out_reg, first_reg, second_reg);
+        break;
+      // There is no EON on arm.
+      case HInstruction::kXor:
+      default:
+        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
+        UNREACHABLE();
+    }
+    return;
+
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    vixl32::Register first_low = LowRegisterFrom(first);
+    vixl32::Register first_high = HighRegisterFrom(first);
+    vixl32::Register second_low = LowRegisterFrom(second);
+    vixl32::Register second_high = HighRegisterFrom(second);
+    vixl32::Register out_low = LowRegisterFrom(out);
+    vixl32::Register out_high = HighRegisterFrom(out);
+
+    switch (instruction->GetOpKind()) {
+      case HInstruction::kAnd:
+        __ Bic(out_low, first_low, second_low);
+        __ Bic(out_high, first_high, second_high);
+        break;
+      case HInstruction::kOr:
+        __ Orn(out_low, first_low, second_low);
+        __ Orn(out_high, first_high, second_high);
+        break;
+      // There is no EON on arm.
+      case HInstruction::kXor:
+      default:
+        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
+        UNREACHABLE();
+    }
+  }
+}
+
 // TODO(VIXL): Remove optimizations in the helper when they are implemented in vixl.
 void InstructionCodeGeneratorARMVIXL::GenerateAndConst(vixl32::Register out,
                                                        vixl32::Register first,
@@ -5858,6 +6002,32 @@
   __ Blx(lr);
 }
 
+void LocationsBuilderARMVIXL::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
+  locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
+                     Location::RequiresRegister());
+  locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
+  locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
+  vixl32::Register res = OutputRegister(instr);
+  vixl32::Register accumulator =
+      InputRegisterAt(instr, HMultiplyAccumulate::kInputAccumulatorIndex);
+  vixl32::Register mul_left =
+      InputRegisterAt(instr, HMultiplyAccumulate::kInputMulLeftIndex);
+  vixl32::Register mul_right =
+      InputRegisterAt(instr, HMultiplyAccumulate::kInputMulRightIndex);
+
+  if (instr->GetOpKind() == HInstruction::kAdd) {
+    __ Mla(res, mul_left, mul_right, accumulator);
+  } else {
+    __ Mls(res, mul_left, mul_right, accumulator);
+  }
+}
+
 void LocationsBuilderARMVIXL::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
   // Nothing to do, this should be removed during prepare for register allocator.
   LOG(FATAL) << "Unreachable";
@@ -5952,6 +6122,8 @@
     vixl32::Register target_address = table_base;
     __ Add(target_address, table_base, jump_offset);
     __ Bx(target_address);
+
+    jump_table->EmitTable(codegen_);
   }
 }
 
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index ccd866c..302ee38 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -112,6 +112,7 @@
   M(ArraySet)                                   \
   M(Below)                                      \
   M(BelowOrEqual)                               \
+  M(BitwiseNegatedRight)                        \
   M(BooleanNot)                                 \
   M(BoundsCheck)                                \
   M(BoundType)                                  \
@@ -136,6 +137,7 @@
   M(InstanceFieldSet)                           \
   M(InstanceOf)                                 \
   M(IntConstant)                                \
+  M(IntermediateAddress)                        \
   M(InvokeInterface)                            \
   M(InvokeStaticOrDirect)                       \
   M(InvokeUnresolved)                           \
@@ -149,6 +151,7 @@
   M(MemoryBarrier)                              \
   M(MonitorOperation)                           \
   M(Mul)                                        \
+  M(MultiplyAccumulate)                         \
   M(NativeDebugInfo)                            \
   M(Neg)                                        \
   M(NewArray)                                   \
@@ -186,24 +189,33 @@
 // TODO: Remove once the VIXL32 backend is implemented completely.
 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)   \
   M(ArmDexCacheArraysBase)                      \
-  M(BitwiseNegatedRight)                        \
-  M(IntermediateAddress)                        \
-  M(MultiplyAccumulate)                         \
 
 class CodeGeneratorARMVIXL;
 
 class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> {
  public:
+  typedef vixl::aarch32::Literal<int32_t> IntLiteral;
+
   explicit JumpTableARMVIXL(HPackedSwitch* switch_instr)
-      : switch_instr_(switch_instr), table_start_() {}
+      : switch_instr_(switch_instr),
+        table_start_(),
+        bb_addresses_(switch_instr->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+    uint32_t num_entries = switch_instr_->GetNumEntries();
+    for (uint32_t i = 0; i < num_entries; i++) {
+      IntLiteral *lit = new IntLiteral(0);
+      bb_addresses_.emplace_back(lit);
+    }
+  }
 
   vixl::aarch32::Label* GetTableStartLabel() { return &table_start_; }
 
   void EmitTable(CodeGeneratorARMVIXL* codegen);
+  void FixTable(CodeGeneratorARMVIXL* codegen);
 
  private:
   HPackedSwitch* const switch_instr_;
   vixl::aarch32::Label table_start_;
+  ArenaVector<std::unique_ptr<IntLiteral>> bb_addresses_;
 
   DISALLOW_COPY_AND_ASSIGN(JumpTableARMVIXL);
 };
@@ -513,7 +525,7 @@
 
   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
 
-  void EmitJumpTables();
+  void FixJumpTables();
   void GenerateMemoryBarrier(MemBarrierKind kind);
   void Finalize(CodeAllocator* allocator) OVERRIDE;
   void SetupBlockedRegisters() const OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 5997b42..3849437 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6865,24 +6865,24 @@
                                           temp_loc,
                                           iftable_offset,
                                           kWithoutReadBarrier);
-        // Null iftable means it is empty.
-        __ testl(temp, temp);
-        __ j(kZero, type_check_slow_path->GetEntryLabel());
-
-        // Loop through the iftable and check if any class matches.
+        // Iftable is never null.
         __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
-
+        // Loop through the iftable and check if any class matches.
         NearLabel start_loop;
         __ Bind(&start_loop);
-        __ cmpl(cls.AsRegister<Register>(), Address(temp, object_array_data_offset));
-        __ j(kEqual, &done);  // Return if same class.
-        // Go to next interface.
-        __ addl(temp, Immediate(2 * kHeapReferenceSize));
+        // Need to subtract first to handle the empty array case.
         __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2));
-        __ j(kNotZero, &start_loop);
+        __ j(kNegative, type_check_slow_path->GetEntryLabel());
+        // Go to next interface if the classes do not match.
+        __ cmpl(cls.AsRegister<Register>(),
+                CodeGeneratorX86::ArrayAddress(temp,
+                                               maybe_temp2_loc,
+                                               TIMES_4,
+                                               object_array_data_offset));
+        __ j(kNotEqual, &start_loop);
+      } else {
+        __ jmp(type_check_slow_path->GetEntryLabel());
       }
-
-      __ jmp(type_check_slow_path->GetEntryLabel());
       break;
     }
   }
@@ -7578,7 +7578,7 @@
     // The value to patch is the distance from the offset in the constant area
     // from the address computed by the HX86ComputeBaseMethodAddress instruction.
     int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
-    int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();;
+    int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();
 
     // Patch in the right value.
     region.StoreUnaligned<int32_t>(pos - 4, relative_position);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 9e424ad..02f5491 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -6276,23 +6276,24 @@
                                           temp_loc,
                                           iftable_offset,
                                           kWithoutReadBarrier);
-        // Null iftable means it is empty.
-        __ testl(temp, temp);
-        __ j(kZero, type_check_slow_path->GetEntryLabel());
-
-        // Loop through the iftable and check if any class matches.
+        // Iftable is never null.
         __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
-
+        // Loop through the iftable and check if any class matches.
         NearLabel start_loop;
         __ Bind(&start_loop);
-        __ cmpl(cls.AsRegister<CpuRegister>(), Address(temp, object_array_data_offset));
-        __ j(kEqual, &done);  // Return if same class.
-        // Go to next interface.
-        __ addl(temp, Immediate(2 * kHeapReferenceSize));
+        // Need to subtract first to handle the empty array case.
         __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
-        __ j(kNotZero, &start_loop);
+        __ j(kNegative, type_check_slow_path->GetEntryLabel());
+        // Go to next interface if the classes do not match.
+        __ cmpl(cls.AsRegister<CpuRegister>(),
+                CodeGeneratorX86_64::ArrayAddress(temp,
+                                                  maybe_temp2_loc,
+                                                  TIMES_4,
+                                                  object_array_data_offset));
+        __ j(kNotEqual, &start_loop);  // Return if same class.
+      } else {
+        __ jmp(type_check_slow_path->GetEntryLabel());
       }
-      __ jmp(type_check_slow_path->GetEntryLabel());
       break;
   }
 
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index c8c4ca7..b44137d 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1723,7 +1723,10 @@
     if (dex_pc_in_map == dex_pc) {
       return value_in_map;
     } else {
-      skipped_interpreter_metadata_.Put(dex_pc_in_map, value_in_map);
+      // Overwrite and not Put, as quickened CHECK-CAST has two entries with
+      // the same dex_pc. This is OK, because the compiler does not care about those
+      // entries.
+      skipped_interpreter_metadata_.Overwrite(dex_pc_in_map, value_in_map);
     }
   }
 }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 830f834..85519c9 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -625,17 +625,14 @@
   UNUSED(codegen);  // To avoid compilation error when compiling for svelte
   OptimizingCompilerStats* stats = compilation_stats_.get();
   ArenaAllocator* arena = graph->GetArena();
-#ifdef ART_USE_VIXL_ARM_BACKEND
-  UNUSED(arena);
-  UNUSED(pass_observer);
-  UNUSED(stats);
-#endif
   switch (instruction_set) {
-#if defined(ART_ENABLE_CODEGEN_arm) && !defined(ART_USE_VIXL_ARM_BACKEND)
+#if defined(ART_ENABLE_CODEGEN_arm)
     case kThumb2:
     case kArm: {
+#ifndef ART_USE_VIXL_ARM_BACKEND
       arm::DexCacheArrayFixups* fixups =
           new (arena) arm::DexCacheArrayFixups(graph, codegen, stats);
+#endif
       arm::InstructionSimplifierArm* simplifier =
           new (arena) arm::InstructionSimplifierArm(graph, stats);
       SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
@@ -644,7 +641,9 @@
         simplifier,
         side_effects,
         gvn,
+#ifndef ART_USE_VIXL_ARM_BACKEND
         fixups
+#endif
       };
       RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer);
       break;
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index 8a9fd90..23b2774 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -49,7 +49,7 @@
   return dwarf::Reg::ArmFp(static_cast<int>(reg.GetCode()));
 }
 
-static constexpr size_t kFramePointerSize = static_cast<size_t>(kArmPointerSize);;
+static constexpr size_t kFramePointerSize = static_cast<size_t>(kArmPointerSize);
 
 void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size,
                                           ManagedRegister method_reg,
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index bc9ca6d..7c55659 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -350,7 +350,8 @@
   const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
   for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
     dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
-    if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, class_index)) {
+    uint16_t type_idx = class_def->ClassType()->GetIndex();
+    if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
       continue;
     }
     dumper->DumpAddressRange(class_def, class_index);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 3d208b5..4c01c14 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -2783,7 +2783,7 @@
 
     bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
 
-    if (klass->GetIfTable() == nullptr) {
+    if (klass->GetIfTable()->Count() == 0) {
       DCHECK(result);
     }
 
@@ -2889,25 +2889,23 @@
     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 (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 class_hash, name_hash, signature_hash;
-          ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
-          uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
-          std::cerr << "    " << iface_method.PrettyMethod(true)
-              << " slot=" << imt_slot
-              << std::hex
-              << " class_hash=0x" << class_hash
-              << " name_hash=0x" << name_hash
-              << " signature_hash=0x" << signature_hash
-              << std::dec
-              << std::endl;
-        }
+      for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
+        uint32_t class_hash, name_hash, signature_hash;
+        ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
+        uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
+        std::cerr << "    " << iface_method.PrettyMethod(true)
+            << " slot=" << imt_slot
+            << std::hex
+            << " class_hash=0x" << class_hash
+            << " name_hash=0x" << name_hash
+            << " signature_hash=0x" << signature_hash
+            << std::dec
+            << std::endl;
       }
     }
   }
@@ -2972,18 +2970,16 @@
         } 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 = iface_method.PrettyMethod(true);
-                    if (StartsWith(i_name, method.c_str())) {
-                      std::cerr << "  Slot " << index << " (1)" << std::endl;
-                      std::cerr << "    " << p_name << " (" << i_name << ")" << std::endl;
-                    }
+          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 = iface_method.PrettyMethod(true);
+                  if (StartsWith(i_name, method.c_str())) {
+                    std::cerr << "  Slot " << index << " (1)" << std::endl;
+                    std::cerr << "    " << p_name << " (" << i_name << ")" << std::endl;
                   }
                 }
               }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 3c8c1a3..db28a3f 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -498,7 +498,7 @@
   return true;
 }
 
-class PatchOatArtFieldVisitor : public ArtFieldVisitor {
+class PatchOat::PatchOatArtFieldVisitor : public ArtFieldVisitor {
  public:
   explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
 
@@ -517,7 +517,7 @@
   image_header->VisitPackedArtFields(&visitor, heap_->Begin());
 }
 
-class PatchOatArtMethodVisitor : public ArtMethodVisitor {
+class PatchOat::PatchOatArtMethodVisitor : public ArtMethodVisitor {
  public:
   explicit PatchOatArtMethodVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
 
@@ -558,7 +558,7 @@
       pointer_size);
 }
 
-class FixupRootVisitor : public RootVisitor {
+class PatchOat::FixupRootVisitor : public RootVisitor {
  public:
   explicit FixupRootVisitor(const PatchOat* patch_oat) : patch_oat_(patch_oat) {
   }
@@ -610,7 +610,7 @@
 }
 
 
-class RelocatedPointerVisitor {
+class PatchOat::RelocatedPointerVisitor {
  public:
   explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {}
 
@@ -762,16 +762,14 @@
     if (vtable != nullptr) {
       vtable->Fixup(RelocatedCopyOfFollowImages(vtable), pointer_size, native_visitor);
     }
-    auto* iftable = klass->GetIfTable();
-    if (iftable != nullptr) {
-      for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
-        if (iftable->GetMethodArrayCount(i) > 0) {
-          auto* method_array = iftable->GetMethodArray(i);
-          CHECK(method_array != nullptr);
-          method_array->Fixup(RelocatedCopyOfFollowImages(method_array),
-                              pointer_size,
-                              native_visitor);
-        }
+    mirror::IfTable* iftable = klass->GetIfTable();
+    for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
+      if (iftable->GetMethodArrayCount(i) > 0) {
+        auto* method_array = iftable->GetMethodArray(i);
+        CHECK(method_array != nullptr);
+        method_array->Fixup(RelocatedCopyOfFollowImages(method_array),
+                            pointer_size,
+                            native_visitor);
       }
     }
   } else if (object->GetClass() == mirror::Method::StaticClass() ||
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index e7a3e91..a519631 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -230,10 +230,11 @@
 
   TimingLogger* timings_;
 
-  friend class FixupRootVisitor;
-  friend class RelocatedPointerVisitor;
-  friend class PatchOatArtFieldVisitor;
-  friend class PatchOatArtMethodVisitor;
+  class FixupRootVisitor;
+  class RelocatedPointerVisitor;
+  class PatchOatArtFieldVisitor;
+  class PatchOatArtMethodVisitor;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(PatchOat);
 };
 
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 2a12f1d..de72d3a 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -86,7 +86,7 @@
   DefaultInitEntryPoints(jpoints, qpoints);
 
   // Cast
-  qpoints->pInstanceofNonTrivial = artInstanceOfFromCode;;
+  qpoints->pInstanceofNonTrivial = artInstanceOfFromCode;
   qpoints->pCheckInstanceOf = art_quick_check_instance_of;
 
   // Math
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index cb0bdbf..6a442a5 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -156,17 +156,24 @@
   // JNI
   qpoints->pJniMethodStart = JniMethodStart;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodStart), "Non-direct C stub marked direct.");
+  qpoints->pJniMethodFastStart = JniMethodFastStart;
+  static_assert(!IsDirectEntrypoint(kQuickJniMethodFastStart), "Non-direct C stub marked direct.");
   qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodStartSynchronized),
                 "Non-direct C stub marked direct.");
   qpoints->pJniMethodEnd = JniMethodEnd;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodEnd), "Non-direct C stub marked direct.");
+  qpoints->pJniMethodFastEnd = JniMethodFastEnd;
+  static_assert(!IsDirectEntrypoint(kQuickJniMethodFastEnd), "Non-direct C stub marked direct.");
   qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodEndSynchronized),
                 "Non-direct C stub marked direct.");
   qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodEndWithReference),
                 "Non-direct C stub marked direct.");
+  qpoints->pJniMethodFastEndWithReference = JniMethodFastEndWithReference;
+  static_assert(!IsDirectEntrypoint(kQuickJniMethodFastEndWithReference),
+                "Non-direct C stub marked direct.");
   qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
   static_assert(!IsDirectEntrypoint(kQuickJniMethodEndWithReferenceSynchronized),
                 "Non-direct C stub marked direct.");
diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc
index 077d2db..cb3dfec 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -17,6 +17,7 @@
 #include "context_x86.h"
 
 #include "base/bit_utils.h"
+#include "base/memory_tool.h"
 #include "quick/quick_method_frame_info.h"
 
 namespace art {
@@ -102,6 +103,7 @@
   uintptr_t esp = gprs[kNumberOfCpuRegisters - ESP - 1] - sizeof(intptr_t);
   gprs[kNumberOfCpuRegisters] = esp;
   *(reinterpret_cast<uintptr_t*>(esp)) = eip_;
+  MEMORY_TOOL_HANDLE_NO_RETURN;
   __asm__ __volatile__(
       "movl %1, %%ebx\n\t"          // Address base of FPRs.
       "movsd 0(%%ebx), %%xmm0\n\t"  // Load up XMM0-XMM7.
diff --git a/runtime/base/memory_tool.h b/runtime/base/memory_tool.h
index e1a2e07..42cbaa0 100644
--- a/runtime/base/memory_tool.h
+++ b/runtime/base/memory_tool.h
@@ -40,7 +40,10 @@
 constexpr bool kMemoryToolIsAvailable = false;
 #endif
 
+extern "C" void __asan_handle_no_return();
+
 #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#define MEMORY_TOOL_HANDLE_NO_RETURN __asan_handle_no_return()
 #define RUNNING_ON_MEMORY_TOOL 1U
 constexpr bool kMemoryToolIsValgrind = false;
 constexpr bool kMemoryToolDetectsLeaks = true;
@@ -55,6 +58,7 @@
 #define MEMORY_TOOL_MAKE_UNDEFINED(p, s) VALGRIND_MAKE_MEM_UNDEFINED(p, s)
 #define MEMORY_TOOL_MAKE_DEFINED(p, s) VALGRIND_MAKE_MEM_DEFINED(p, s)
 #define ATTRIBUTE_NO_SANITIZE_ADDRESS
+#define MEMORY_TOOL_HANDLE_NO_RETURN do { } while (0)
 #define RUNNING_ON_MEMORY_TOOL RUNNING_ON_VALGRIND
 constexpr bool kMemoryToolIsAvailable = true;
 constexpr bool kMemoryToolIsValgrind = true;
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 350855b..7359243 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -69,7 +69,7 @@
   Thread::PoisonObjectPointersIfDebug();
   ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
   // MethodVerifier refuses methods with string_idx out of bounds.
-  DCHECK_LT(string_idx, declaring_class->GetDexFile().NumStringIds());;
+  DCHECK_LT(string_idx, declaring_class->GetDexFile().NumStringIds());
   ObjPtr<mirror::String> string =
         mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
                                            string_idx,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ac5e6aa..4905514 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -475,6 +475,9 @@
   SetClassRoot(kJavaLangString, java_lang_String.Get());
   SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get());
 
+  // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set.
+  java_lang_Object->SetIfTable(AllocIfTable(self, 0));
+
   // Setup the primitive type classes.
   SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
   SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
@@ -916,13 +919,11 @@
         SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr, image_spaces);
       }
     }
-    auto* iftable = klass->GetIfTable();
-    if (iftable != nullptr) {
-      for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
-        if (iftable->GetMethodArrayCount(i) > 0) {
-          SanityCheckArtMethodPointerArray(
-              iftable->GetMethodArray(i), nullptr, pointer_size, image_spaces);
-        }
+    mirror::IfTable* iftable = klass->GetIfTable();
+    for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
+      if (iftable->GetMethodArrayCount(i) > 0) {
+        SanityCheckArtMethodPointerArray(
+            iftable->GetMethodArray(i), nullptr, pointer_size, image_spaces);
       }
     }
   }
@@ -3401,7 +3402,8 @@
 }
 
 mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
-  ObjPtr<mirror::Class> klass = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_));
+  ObjPtr<mirror::Class> klass =
+      AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_));
   if (UNLIKELY(klass == nullptr)) {
     self->AssertPendingOOMException();
     return nullptr;
@@ -3419,10 +3421,12 @@
   ObjectLock<mirror::Class> lock(self, h_class);
   h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   h_class->SetPrimitiveType(type);
+  h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
   mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self);
   const char* descriptor = Primitive::Descriptor(type);
-  ObjPtr<mirror::Class> existing = InsertClass(descriptor, h_class.Get(),
-                                        ComputeModifiedUtf8Hash(descriptor));
+  ObjPtr<mirror::Class> existing = InsertClass(descriptor,
+                                               h_class.Get(),
+                                               ComputeModifiedUtf8Hash(descriptor));
   CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed";
   return h_class.Get();
 }
@@ -4121,6 +4125,8 @@
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
   klass->SetName(soa.Decode<mirror::String>(name));
   klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
+  // Object has an empty iftable, copy it for that reason.
+  klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
   mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
   std::string descriptor(GetDescriptorForProxy(klass.Get()));
   const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
@@ -6381,16 +6387,18 @@
 bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle<mirror::Class> klass,
                                             Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
   StackHandleScope<1> hs(self);
-  const size_t super_ifcount =
-      klass->HasSuperClass() ? klass->GetSuperClass()->GetIfTableCount() : 0U;
+  const bool has_superclass = klass->HasSuperClass();
+  const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
   const bool have_interfaces = interfaces.Get() != nullptr;
   const size_t num_interfaces =
       have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces();
   if (num_interfaces == 0) {
     if (super_ifcount == 0) {
+      if (LIKELY(has_superclass)) {
+        klass->SetIfTable(klass->GetSuperClass()->GetIfTable());
+      }
       // Class implements no interfaces.
       DCHECK_EQ(klass->GetIfTableCount(), 0);
-      DCHECK(klass->GetIfTable() == nullptr);
       return true;
     }
     // Class implements same interfaces as parent, are any of these not marker interfaces?
@@ -6583,7 +6591,7 @@
   } else {
     // No imt in the super class, need to reconstruct from the iftable.
     ObjPtr<mirror::IfTable> if_table = super_class->GetIfTable();
-    if (if_table != nullptr) {
+    if (if_table->Count() != 0) {
       // Ignore copied methods since we will handle these in LinkInterfaceMethods.
       FillIMTFromIfTable(if_table,
                          unimplemented_method,
@@ -8358,17 +8366,16 @@
       }
       ObjPtr<mirror::DexCache> klass_dex_cache = klass->GetDexCache();
       if (klass_dex_cache == dex_cache) {
-        const size_t class_def_idx = klass->GetDexClassDefIndex();
         DCHECK(klass->IsResolved());
-        CHECK_LT(class_def_idx, num_class_defs);
-        class_set.insert(class_def_idx);
+        CHECK_LT(klass->GetDexClassDefIndex(), num_class_defs);
+        class_set.insert(klass->GetDexTypeIndex());
       }
     }
 
     if (!class_set.empty()) {
       auto it = ret.find(resolved_classes);
       if (it != ret.end()) {
-        // Already have the key, union the class def idxs.
+        // Already have the key, union the class type indexes.
         it->AddClasses(class_set.begin(), class_set.end());
       } else {
         resolved_classes.AddClasses(class_set.begin(), class_set.end());
@@ -8411,13 +8418,8 @@
       VLOG(profiler) << "Found opened dex file for " << dex_file->GetLocation() << " with "
                      << info.GetClasses().size() << " classes";
       DCHECK_EQ(dex_file->GetLocationChecksum(), info.GetLocationChecksum());
-      for (uint16_t class_def_idx : info.GetClasses()) {
-        if (class_def_idx >= dex_file->NumClassDefs()) {
-          LOG(WARNING) << "Class def index " << class_def_idx << " >= " << dex_file->NumClassDefs();
-          continue;
-        }
-        const DexFile::TypeId& type_id = dex_file->GetTypeId(
-            dex_file->GetClassDef(class_def_idx).class_idx_);
+      for (uint16_t type_idx : info.GetClasses()) {
+        const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         ret.insert(descriptor);
       }
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index ab2d9d0..44590ba 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -101,7 +101,8 @@
     EXPECT_EQ(0U, primitive->NumDirectInterfaces());
     EXPECT_FALSE(primitive->HasVTable());
     EXPECT_EQ(0, primitive->GetIfTableCount());
-    EXPECT_TRUE(primitive->GetIfTable() == nullptr);
+    EXPECT_TRUE(primitive->GetIfTable() != nullptr);
+    EXPECT_EQ(primitive->GetIfTable()->Count(), 0u);
     EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
   }
 
diff --git a/runtime/class_table.h b/runtime/class_table.h
index bc9eaf4..558c144 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -48,7 +48,7 @@
     uint32_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS;
     // Same class loader and descriptor.
     bool operator()(const GcRoot<mirror::Class>& a, const GcRoot<mirror::Class>& b) const
-        NO_THREAD_SAFETY_ANALYSIS;;
+        NO_THREAD_SAFETY_ANALYSIS;
     // Same descriptor.
     bool operator()(const GcRoot<mirror::Class>& a, const char* descriptor) const
         NO_THREAD_SAFETY_ANALYSIS;
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 8eb1a79..99b9f9d 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -480,6 +480,18 @@
     insns[1] = val;
   }
 
+  void SetVRegA_21c(uint8_t val) {
+    DCHECK(FormatOf(Opcode()) == k21c);
+    uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+    insns[0] = (val << 8) | (insns[0] & 0x00ff);
+  }
+
+  void SetVRegB_21c(uint16_t val) {
+    DCHECK(FormatOf(Opcode()) == k21c);
+    uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+    insns[1] = val;
+  }
+
   // Returns the format of the given opcode.
   static Format FormatOf(Code opcode) {
     return kInstructionFormats[opcode];
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index ddc3852..f0e619d 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -264,6 +264,10 @@
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Heap() entering";
   }
+  if (kUseReadBarrier) {
+    CHECK_EQ(foreground_collector_type_, kCollectorTypeCC);
+    CHECK_EQ(background_collector_type_, kCollectorTypeCCBackground);
+  }
   CHECK_GE(large_object_threshold, kMinLargeObjectThreshold);
   ScopedTrace trace(__FUNCTION__);
   Runtime* const runtime = Runtime::Current();
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 0b602e9..6019540 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1002,7 +1002,7 @@
         mirror::IfTable* iftable = as_klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
         // Ensure iftable arrays are fixed up since we need GetMethodArray to return the valid
         // contents.
-        if (iftable != nullptr && IsInAppImage(iftable)) {
+        if (IsInAppImage(iftable)) {
           operator()(iftable);
           for (int32_t i = 0, count = iftable->Count(); i < count; ++i) {
             if (iftable->GetMethodArrayCount<kVerifyNone, kWithoutReadBarrier>(i) > 0) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index cb775cd..8c63a9e 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1020,7 +1020,7 @@
   } else {
     DCHECK(!is_range);
     ArtField* field = method_handle->GetTargetField();
-    Primitive::Type field_type = field->GetTypeAsPrimitiveType();;
+    Primitive::Type field_type = field->GetTypeAsPrimitiveType();
 
     switch (handle_kind) {
       case kInstanceGet: {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 2257fd6..a5b1038 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -424,7 +424,7 @@
 
   std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(jar_file.c_str(), error_msg));
   if (zip_archive == nullptr) {
-    return nullptr;;
+    return nullptr;
   }
   std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(entry_name, error_msg));
   if (zip_entry == nullptr) {
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 4c10063..dac2e60 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -114,7 +114,7 @@
   } else {
     jit_options->invoke_transition_weight_ = std::max(
         jit_options->warmup_threshold_ / Jit::kDefaultInvokeTransitionWeightRatio,
-        static_cast<size_t>(1));;
+        static_cast<size_t>(1));
   }
 
   return jit_options;
@@ -274,6 +274,15 @@
               << ArtMethod::PrettyMethod(method_to_compile)
               << " osr=" << std::boolalpha << osr;
   }
+  if (kIsDebugBuild) {
+    if (self->IsExceptionPending()) {
+      mirror::Throwable* exception = self->GetException();
+      LOG(FATAL) << "No pending exception expected after compiling "
+                 << ArtMethod::PrettyMethod(method)
+                 << ": "
+                 << exception->Dump();
+    }
+  }
   return success;
 }
 
@@ -701,5 +710,24 @@
   }
 }
 
+ScopedJitSuspend::ScopedJitSuspend() {
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  was_on_ = (jit != nullptr) && (jit->GetThreadPool() != nullptr);
+  if (was_on_) {
+    Thread* self = Thread::Current();
+    jit->WaitForCompilationToFinish(self);
+    jit->GetThreadPool()->StopWorkers(self);
+    jit->WaitForCompilationToFinish(self);
+  }
+}
+
+ScopedJitSuspend::~ScopedJitSuspend() {
+  if (was_on_) {
+    DCHECK(Runtime::Current()->GetJit() != nullptr);
+    DCHECK(Runtime::Current()->GetJit()->GetThreadPool() != nullptr);
+    Runtime::Current()->GetJit()->GetThreadPool()->StartWorkers(Thread::Current());
+  }
+}
+
 }  // namespace jit
 }  // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index a782437..a230c78 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -175,6 +175,10 @@
 
   static bool LoadCompilerLibrary(std::string* error_msg);
 
+  ThreadPool* GetThreadPool() const {
+    return thread_pool_.get();
+  }
+
  private:
   Jit();
 
@@ -278,6 +282,16 @@
   DISALLOW_COPY_AND_ASSIGN(JitOptions);
 };
 
+// Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce.
+class ScopedJitSuspend {
+ public:
+  ScopedJitSuspend();
+  ~ScopedJitSuspend();
+
+ private:
+  bool was_on_;
+};
+
 }  // namespace jit
 }  // namespace art
 
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index f535151..b9f5981 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -37,7 +37,7 @@
 namespace art {
 
 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
-const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '1', '\0' };
+const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '2', '\0' };
 
 static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
 
@@ -282,12 +282,12 @@
 
 bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
                                            uint32_t checksum,
-                                           uint16_t class_idx) {
+                                           uint16_t type_idx) {
   DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
   if (data == nullptr) {
     return false;
   }
-  data->class_set.insert(class_idx);
+  data->class_set.insert(type_idx);
   return true;
 }
 
@@ -304,8 +304,8 @@
   }
 
   for (uint16_t i = 0; i < class_set_size; i++) {
-    uint16_t class_def_idx = line_buffer.ReadUintAndAdvance<uint16_t>();
-    if (!AddClassIndex(dex_location, checksum, class_def_idx)) {
+    uint16_t type_idx = line_buffer.ReadUintAndAdvance<uint16_t>();
+    if (!AddClassIndex(dex_location, checksum, type_idx)) {
       return false;
     }
   }
@@ -569,14 +569,14 @@
   return false;
 }
 
-bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, uint16_t class_def_idx) const {
+bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, uint16_t type_idx) const {
   auto info_it = info_.find(GetProfileDexFileKey(dex_file.GetLocation()));
   if (info_it != info_.end()) {
     if (!ChecksumMatch(dex_file, info_it->second.checksum)) {
       return false;
     }
     const std::set<uint16_t>& classes = info_it->second.class_set;
-    return classes.find(class_def_idx) != classes.end();
+    return classes.find(type_idx) != classes.end();
   }
   return false;
 }
@@ -637,7 +637,7 @@
     os << "\n\tclasses: ";
     for (const auto class_it : dex_data.class_set) {
       if (dex_file != nullptr) {
-        os << "\n\t\t" << dex_file->GetClassDescriptor(dex_file->GetClassDef(class_it));
+        os << "\n\t\t" << dex_file->PrettyType(class_it);
       } else {
         os << class_it << ",";
       }
@@ -702,11 +702,11 @@
     }
 
     for (uint16_t c = 0; c < number_of_classes; c++) {
-      uint16_t class_idx = rand() % max_classes;
+      uint16_t type_idx = rand() % max_classes;
       if (c < (number_of_classes / kFavorSplit)) {
-        class_idx %= kFavorFirstN;
+        type_idx %= kFavorFirstN;
       }
-      info.AddClassIndex(profile_key, 0, class_idx);
+      info.AddClassIndex(profile_key, 0, type_idx);
     }
   }
   return info.Save(fd);
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index fdca078..f8ed573 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -65,8 +65,8 @@
   // Returns true if the method reference is present in the profiling info.
   bool ContainsMethod(const MethodReference& method_ref) const;
 
-  // Returns true if the class is present in the profiling info.
-  bool ContainsClass(const DexFile& dex_file, uint16_t class_def_idx) const;
+  // Returns true if the class's type is present in the profiling info.
+  bool ContainsClass(const DexFile& dex_file, uint16_t type_idx) const;
 
   // Dumps all the loaded profile info into a string and returns it.
   // If dex_files is not null then the method indices will be resolved to their
@@ -115,7 +115,7 @@
 
   DexFileData* GetOrAddDexFileData(const std::string& dex_location, uint32_t checksum);
   bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
-  bool AddClassIndex(const std::string& dex_location, uint32_t checksum, uint16_t class_idx);
+  bool AddClassIndex(const std::string& dex_location, uint32_t checksum, uint16_t type_idx);
   bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
 
   // Parsing functionality.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index bbdb2af..9a6d60e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -526,18 +526,17 @@
 template<VerifyObjectFlags kVerifyFlags,
          ReadBarrierOption kReadBarrierOption>
 inline IfTable* Class::GetIfTable() {
-  return GetFieldObject<IfTable, kVerifyFlags, kReadBarrierOption>(IfTableOffset());
+  ObjPtr<IfTable> ret = GetFieldObject<IfTable, kVerifyFlags, kReadBarrierOption>(IfTableOffset());
+  DCHECK(ret != nullptr) << PrettyClass(this);
+  return ret.Ptr();
 }
 
 inline int32_t Class::GetIfTableCount() {
-  ObjPtr<IfTable> iftable = GetIfTable();
-  if (iftable == nullptr) {
-    return 0;
-  }
-  return iftable->Count();
+  return GetIfTable()->Count();
 }
 
 inline void Class::SetIfTable(ObjPtr<IfTable> new_iftable) {
+  DCHECK(new_iftable != nullptr) << PrettyClass(this);
   SetFieldObject<false>(IfTableOffset(), new_iftable);
 }
 
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index be5d446..0fdf132 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -150,12 +150,12 @@
       uintptr_t fake_address_dependency;
       if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
         baker_non_gray_case = true;
-        DCHECK_EQ(fake_address_dependency, 0U) << fake_address_dependency;
+        DCHECK_EQ(fake_address_dependency, 0U);
         src.Assign(reinterpret_cast<ObjectArray<T>*>(
             reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
         for (int i = 0; i < count; ++i) {
           // We can skip the RB here because 'src' isn't gray.
-          Object* obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
+          T* obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
               src_pos + i);
           SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
         }
@@ -164,7 +164,7 @@
     if (!baker_non_gray_case) {
       for (int i = 0; i < count; ++i) {
         // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
-        Object* obj = src->GetWithoutChecks(src_pos + i);
+        T* obj = src->GetWithoutChecks(src_pos + i);
         SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
       }
     }
@@ -175,12 +175,12 @@
       uintptr_t fake_address_dependency;
       if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
         baker_non_gray_case = true;
-        DCHECK_EQ(fake_address_dependency, 0U) << fake_address_dependency;
+        DCHECK_EQ(fake_address_dependency, 0U);
         src.Assign(reinterpret_cast<ObjectArray<T>*>(
             reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
         for (int i = count - 1; i >= 0; --i) {
           // We can skip the RB here because 'src' isn't gray.
-          Object* obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
+          T* obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
               src_pos + i);
           SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
         }
@@ -189,7 +189,7 @@
     if (!baker_non_gray_case) {
       for (int i = count - 1; i >= 0; --i) {
         // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
-        Object* obj = src->GetWithoutChecks(src_pos + i);
+        T* obj = src->GetWithoutChecks(src_pos + i);
         SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
       }
     }
@@ -225,7 +225,7 @@
     uintptr_t fake_address_dependency;
     if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
       baker_non_gray_case = true;
-      DCHECK_EQ(fake_address_dependency, 0U) << fake_address_dependency;
+      DCHECK_EQ(fake_address_dependency, 0U);
       src.Assign(reinterpret_cast<ObjectArray<T>*>(
           reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
       for (int i = 0; i < count; ++i) {
@@ -266,14 +266,14 @@
   Class* dst_class = GetClass()->GetComponentType();
   Class* lastAssignableElementClass = dst_class;
 
-  Object* o = nullptr;
+  T* o = nullptr;
   int i = 0;
   bool baker_non_gray_case = false;
   if (kUseReadBarrier && kUseBakerReadBarrier) {
     uintptr_t fake_address_dependency;
     if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
       baker_non_gray_case = true;
-      DCHECK_EQ(fake_address_dependency, 0U) << fake_address_dependency;
+      DCHECK_EQ(fake_address_dependency, 0U);
       src.Assign(reinterpret_cast<ObjectArray<T>*>(
           reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
       for (; i < count; ++i) {
diff --git a/runtime/oat.h b/runtime/oat.h
index 3aef707..8c84d42 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', '9', '1', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '9', '2', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 4da1cd2..8a3bac7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -373,6 +373,7 @@
   void Dump(std::ostream& os) const {
     if (gAborting > 1) {
       os << "Runtime aborting --- recursively, so no thread-specific detail!\n";
+      DumpRecursiveAbort(os);
       return;
     }
     gAborting++;
@@ -429,6 +430,21 @@
       }
     }
   }
+
+  // For recursive aborts.
+  void DumpRecursiveAbort(std::ostream& os) const NO_THREAD_SAFETY_ANALYSIS {
+    // The only thing we'll attempt is dumping the native stack of the current thread. We will only
+    // try this if we haven't exceeded an arbitrary amount of recursions, to recover and actually
+    // die.
+    // Note: as we're using a global counter for the recursive abort detection, there is a potential
+    //       race here and it is not OK to just print when the counter is "2" (one from
+    //       Runtime::Abort(), one from previous Dump() call). Use a number that seems large enough.
+    static constexpr size_t kOnlyPrintWhenRecursionLessThan = 100u;
+    if (gAborting < kOnlyPrintWhenRecursionLessThan) {
+      gAborting++;
+      DumpNativeStack(os, GetTid());
+    }
+  }
 };
 
 void Runtime::Abort(const char* msg) {
@@ -443,8 +459,16 @@
 
   // Many people have difficulty distinguish aborts from crashes,
   // so be explicit.
+  // Note: use cerr on the host to print log lines immediately, so we get at least some output
+  //       in case of recursive aborts. We lose annotation with the source file and line number
+  //       here, which is a minor issue. The same is significantly more complicated on device,
+  //       which is why we ignore the issue there.
   AbortState state;
-  LOG(FATAL_WITHOUT_ABORT) << Dumpable<AbortState>(state);
+  if (kIsTargetBuild) {
+    LOG(FATAL_WITHOUT_ABORT) << Dumpable<AbortState>(state);
+  } else {
+    std::cerr << Dumpable<AbortState>(state);
+  }
 
   // Sometimes we dump long messages, and the Android abort message only retains the first line.
   // In those cases, just log the message again, to avoid logcat limits.
@@ -1038,8 +1062,10 @@
                        runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
                        runtime_options.GetOrDefault(Opt::Image),
                        runtime_options.GetOrDefault(Opt::ImageInstructionSet),
-                       xgc_option.collector_type_,
-                       runtime_options.GetOrDefault(Opt::BackgroundGc),
+                       // Override the collector type to CC if the read barrier config.
+                       kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
+                       kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
+                                       : runtime_options.GetOrDefault(Opt::BackgroundGc),
                        runtime_options.GetOrDefault(Opt::LargeObjectSpace),
                        runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
                        runtime_options.GetOrDefault(Opt::ParallelGCThreads),
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index b14f340..65fd999 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -177,7 +177,7 @@
     }
 
     ++waiting_count_;
-    if (waiting_count_ == GetThreadCount() && tasks_.empty()) {
+    if (waiting_count_ == GetThreadCount() && !HasOutstandingTasks()) {
       // We may be done, lets broadcast to the completion condition.
       completion_condition_.Broadcast(self);
     }
@@ -200,7 +200,7 @@
 }
 
 Task* ThreadPool::TryGetTaskLocked() {
-  if (started_ && !tasks_.empty()) {
+  if (HasOutstandingTasks()) {
     Task* task = tasks_.front();
     tasks_.pop_front();
     return task;
@@ -218,7 +218,7 @@
   }
   // Wait until each thread is waiting and the task list is empty.
   MutexLock mu(self, task_queue_lock_);
-  while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) {
+  while (!shutting_down_ && (waiting_count_ != GetThreadCount() || HasOutstandingTasks())) {
     if (!may_hold_locks) {
       completion_condition_.Wait(self);
     } else {
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index b6c6f02..2ff33a6 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -100,7 +100,8 @@
   ThreadPool(const char* name, size_t num_threads);
   virtual ~ThreadPool();
 
-  // Wait for all tasks currently on queue to get completed.
+  // Wait for all tasks currently on queue to get completed. If the pool has been stopped, only
+  // wait till all already running tasks are done.
   void Wait(Thread* self, bool do_work, bool may_hold_locks) REQUIRES(!task_queue_lock_);
 
   size_t GetTaskCount(Thread* self) REQUIRES(!task_queue_lock_);
@@ -130,6 +131,10 @@
     return shutting_down_;
   }
 
+  bool HasOutstandingTasks() const REQUIRES(task_queue_lock_) {
+    return started_ && !tasks_.empty();
+  }
+
   const std::string name_;
   Mutex task_queue_lock_;
   ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_);
diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc
index d5f17d1..14c2c3b 100644
--- a/runtime/thread_pool_test.cc
+++ b/runtime/thread_pool_test.cc
@@ -98,6 +98,29 @@
   thread_pool.Wait(self, false, false);
 }
 
+TEST_F(ThreadPoolTest, StopWait) {
+  Thread* self = Thread::Current();
+  ThreadPool thread_pool("Thread pool test thread pool", num_threads);
+
+  AtomicInteger count(0);
+  static const int32_t num_tasks = num_threads * 100;
+  for (int32_t i = 0; i < num_tasks; ++i) {
+    thread_pool.AddTask(self, new CountTask(&count));
+  }
+
+  // Signal the threads to start processing tasks.
+  thread_pool.StartWorkers(self);
+  usleep(200);
+  thread_pool.StopWorkers(self);
+
+  thread_pool.Wait(self, false, false);  // We should not deadlock here.
+
+  // Drain the task list. Note: we have to restart here, as no tasks will be finished when
+  // the pool is stopped.
+  thread_pool.StartWorkers(self);
+  thread_pool.Wait(self, /* do_work */ true, false);
+}
+
 class TreeTask : public Task {
  public:
   TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index d9e3ea7..ed24611 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -100,8 +100,18 @@
 ALWAYS_INLINE static inline bool FailOrAbort(MethodVerifier* verifier, bool condition,
                                              const char* error_msg, uint32_t work_insn_idx) {
   if (kIsDebugBuild) {
-    // In a debug build, abort if the error condition is wrong.
-    DCHECK(condition) << error_msg << work_insn_idx;
+    // In a debug build, abort if the error condition is wrong. Only warn if
+    // we are already aborting (as this verification is likely run to print
+    // lock information).
+    if (LIKELY(gAborting == 0)) {
+      DCHECK(condition) << error_msg << work_insn_idx;
+    } else {
+      if (!condition) {
+        LOG(ERROR) << error_msg << work_insn_idx;
+        verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx;
+        return true;
+      }
+    }
   } else {
     // In a non-debug build, just fail the class.
     if (!condition) {
diff --git a/test/015-switch/src/Main.java b/test/015-switch/src/Main.java
index 2a7995a..2b724a1 100644
--- a/test/015-switch/src/Main.java
+++ b/test/015-switch/src/Main.java
@@ -113,7 +113,7 @@
     }
 
     // Long packed-switch that might lead to not creating chained-ifs.
-    public static void packedSwitch7(int value) {
+    public static long packedSwitch7(int value) {
         switch (value) {
             case 1:
                 System.out.println(1); break;
@@ -148,6 +148,113 @@
             default:
                 System.out.println("default"); break;
         }
+
+        // Jump tables previously were emitted in the end of the method code buffer. The
+        // following boilerplate code aims to fill the emitted code buffer extensively
+        // and check that even for big method jump table is correctly emitted, its address
+        // is within a range of corresponded pc-relative instructions (this applies to
+        // ARM mainly).
+        long temp = value;
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+        temp = Long.rotateLeft(temp, value);
+
+        return temp;
     }
 
     // Sparse switch, just leave a gap.
diff --git a/test/103-string-append/run b/test/103-string-append/run
deleted file mode 100755
index e27a622..0000000
--- a/test/103-string-append/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-# As this is a performance test we always use the non-debug build.
-exec ${RUN} "${@/#libartd.so/libart.so}"
diff --git a/test/445-checker-licm/expected.txt b/test/445-checker-licm/expected.txt
index e69de29..b0aad4d 100644
--- a/test/445-checker-licm/expected.txt
+++ b/test/445-checker-licm/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 061fe6e..00ce3a9 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -164,8 +164,43 @@
     return result;
   }
 
+  //
+  // All operations up to the null check can be hoisted out of the
+  // loop. The null check itself sees the induction in its environment.
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (before)
+  /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:              LoadClass           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (after)
+  /// CHECK-NOT: LoadClass      loop:{{B\d+}}
+  /// CHECK-NOT: StaticFieldGet loop:{{B\d+}}
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (after)
+  /// CHECK-DAG:              LoadClass           loop:none
+  /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:none
+  /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
+  public static int doWhile(int k) {
+    int i = k;
+    do {
+      i += 2;
+    } while (staticArray[i] == 0);
+    return i;
+  }
+
   public static int staticField = 42;
 
+  public static int[] staticArray = null;
+
   public static void assertEquals(int expected, int actual) {
     if (expected != actual) {
       throw new Error("Expected " + expected + ", got " + actual);
@@ -181,5 +216,24 @@
     assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
     assertEquals(45, invariantBoundIntrinsic(-10));
     assertEquals(30, invariantBodyIntrinsic(2, 3));
+
+    staticArray = null;
+    try {
+      doWhile(0);
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
+    }
+    staticArray = new int[5];
+    staticArray[4] = 1;
+    assertEquals(4, doWhile(-2));
+    assertEquals(4, doWhile(0));
+    assertEquals(4, doWhile(2));
+    try {
+      doWhile(1);
+      throw new Error("Expected IOOBE");
+    } catch (IndexOutOfBoundsException e) {
+    }
+
+    System.out.println("passed");
   }
 }
diff --git a/test/530-checker-loops3/src/Main.java b/test/530-checker-loops3/src/Main.java
index 6b5c657..209786a 100644
--- a/test/530-checker-loops3/src/Main.java
+++ b/test/530-checker-loops3/src/Main.java
@@ -246,7 +246,7 @@
 
     oneConstantIndex(a, b);
     for (int i = 0; i < a.length; i++) {
-      expectEquals(2, a[i]);;
+      expectEquals(2, a[i]);
     }
     try {
       oneConstantIndex(a, b1);
@@ -256,7 +256,7 @@
 
     multipleConstantIndices(a, b);
     for (int i = 0; i < a.length; i++) {
-      expectEquals(6, a[i]);;
+      expectEquals(6, a[i]);
     }
     try {
       multipleConstantIndices(a, b1);
@@ -266,7 +266,7 @@
 
     oneInvariantIndex(a, b, 1);
     for (int i = 0; i < a.length; i++) {
-      expectEquals(2, a[i]);;
+      expectEquals(2, a[i]);
     }
     try {
       oneInvariantIndex(a, b1, 1);
@@ -276,7 +276,7 @@
 
     multipleInvariantIndices(a, b, 1);
     for (int i = 0; i < a.length; i++) {
-      expectEquals(6, a[i]);;
+      expectEquals(6, a[i]);
     }
     try {
       multipleInvariantIndices(a, b1, 1);
@@ -286,18 +286,18 @@
 
     oneUnitStride(a, b);
     for (int i = 0; i < a.length; i++) {
-      expectEquals(i + 1, a[i]);;
+      expectEquals(i + 1, a[i]);
     }
     try {
       oneUnitStride(a, b1);
       throw new Error("Should throw AIOOBE");
     } catch (ArrayIndexOutOfBoundsException e) {
-      expectEquals(100, a[0]);;
+      expectEquals(100, a[0]);
     }
 
     multipleUnitStrides(a, b);
     for (int i = 1; i < a.length - 1; i++) {
-      expectEquals(3 * i + 3, a[i]);;
+      expectEquals(3 * i + 3, a[i]);
     }
     try {
       multipleUnitStrides(a, b1);
@@ -308,7 +308,7 @@
     multipleUnitStridesConditional(a, b);
     for (int i = 2; i < a.length - 2; i++) {
       int e = 3 * i + 3 + (((i & 1) == 0) ? i + 2 : i);
-      expectEquals(e, a[i]);;
+      expectEquals(e, a[i]);
     }
     try {
       multipleUnitStridesConditional(a, b1);
diff --git a/test/586-checker-null-array-get/src/Main.java b/test/586-checker-null-array-get/src/Main.java
index e0782bc..0ea7d34 100644
--- a/test/586-checker-null-array-get/src/Main.java
+++ b/test/586-checker-null-array-get/src/Main.java
@@ -100,7 +100,7 @@
   /// CHECK-DAG:                     Return [<<ArrayGet2>>]
   public static float test1() {
     Test1 test1 = getNullTest1();
-    Test2 test2 = getNullTest2();;
+    Test2 test2 = getNullTest2();
     int[] iarr = test1.iarr;
     float[] farr = test2.farr;
     iarr[0] = iarr[1];
diff --git a/test/611-checker-simplify-if/src/Main.java b/test/611-checker-simplify-if/src/Main.java
index 774f239..c1d75ec 100644
--- a/test/611-checker-simplify-if/src/Main.java
+++ b/test/611-checker-simplify-if/src/Main.java
@@ -144,7 +144,7 @@
   /// CHECK-NOT:                          GreaterThanOrEqual
   /// CHECK-NOT:                          If
   public static void testGreaterCondition(String[] args) {
-    int a = 42;;
+    int a = 42;
     if (args.length == 42) {
       a = 34;
     } else {
diff --git a/test/625-checker-licm-regressions/src/Main.java b/test/625-checker-licm-regressions/src/Main.java
index cc1e07c..f372b1c 100644
--- a/test/625-checker-licm-regressions/src/Main.java
+++ b/test/625-checker-licm-regressions/src/Main.java
@@ -47,14 +47,83 @@
     } while (j < arr.length);
   }
 
+  //
+  // Similar situation as in foo(), but now a proper induction value
+  // is assigned to the field inside the do-while loop.
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (before)
+  /// CHECK-DAG: LoadClass      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: StaticFieldSet loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: NullCheck      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: ArrayLength    loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (after)
+  /// CHECK-DAG: LoadClass      loop:none
+  /// CHECK-DAG: StaticFieldSet loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: NullCheck      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: ArrayLength    loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (after)
+  /// CHECK-NOT: LoadClass      loop:{{B\d+}} outer_loop:none
+  static void bar(int[] arr) {
+    int j = 0;
+    do {
+      j++;
+      sA = j;
+    } while (j < arr.length);
+  }
+
+  //
+  // Similar situation as in bar(), but now an explicit catch
+  // statement may need the latest value of local j.
+  //
+  /// CHECK-START: int Main.catcher(int[]) licm (before)
+  /// CHECK-DAG: NullCheck   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: int Main.catcher(int[]) licm (after)
+  /// CHECK-DAG: NullCheck   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>      outer_loop:none
+  static int catcher(int[] arr) {
+    int j = 0;
+    try {
+      do {
+        j++;
+      } while (j < arr.length);
+    } catch (NullPointerException e) {
+      return -j;  // flag exception with negative value
+    }
+    return j;
+  }
+
   public static void main(String[] args) {
     sA = 0;
     try {
       foo(null);
-    } catch (Exception e) {
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
     }
     expectEquals(1, sA);
 
+    sA = 0;
+    try {
+      bar(null);
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
+    }
+    expectEquals(1, sA);
+
+    for (int i = 0; i < 5; i++) {
+      sA = 0;
+      bar(new int[i]);
+      expectEquals(i == 0 ? 1 : i, sA);
+    }
+
+    expectEquals(-1, catcher(null));
+    for (int i = 0; i < 5; i++) {
+      expectEquals(i == 0 ? 1 : i, catcher(new int[i]));
+    }
+
     System.out.println("passed");
   }
 
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 0c627d6..871902e 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -185,20 +185,194 @@
         }
       }
 
-      lines_.push_back(
-          StringPrintf("%s --(%s)--> %" PRId64 "@%" PRId64 " [size=%" PRId64 ", length=%d]",
-                       referrer_str.c_str(),
-                       GetReferenceTypeStr(reference_kind, reference_info).c_str(),
-                       *tag_ptr,
-                       class_tag,
-                       adapted_size,
-                       length));
+      std::string referree_str = StringPrintf("%" PRId64 "@%" PRId64, *tag_ptr, class_tag);
+
+      lines_.push_back(CreateElem(referrer_str,
+                                  referree_str,
+                                  reference_kind,
+                                  reference_info,
+                                  adapted_size,
+                                  length));
 
       if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && *tag_ptr == 1000) {
         DumpStacks();
       }
     }
 
+    std::vector<std::string> GetLines() const {
+      std::vector<std::string> ret;
+      for (const std::unique_ptr<Elem>& e : lines_) {
+        ret.push_back(e->Print());
+      }
+      return ret;
+    }
+
+   private:
+    // We need to postpone some printing, as required functions are not callback-safe.
+    class Elem {
+     public:
+      Elem(const std::string& referrer, const std::string& referree, jlong size, jint length)
+          : referrer_(referrer), referree_(referree), size_(size), length_(length) {}
+      virtual ~Elem() {}
+
+      std::string Print() const {
+        return StringPrintf("%s --(%s)--> %s [size=%" PRId64 ", length=%d]",
+                            referrer_.c_str(),
+                            PrintArrowType().c_str(),
+                            referree_.c_str(),
+                            size_,
+                            length_);
+      }
+
+     protected:
+      virtual std::string PrintArrowType() const = 0;
+
+     private:
+      std::string referrer_;
+      std::string referree_;
+      jlong size_;
+      jint length_;
+    };
+
+    // For simple or unimplemented cases.
+    class StringElement : public Elem {
+     public:
+      StringElement(const std::string& referrer,
+                   const std::string& referree,
+                   jlong size,
+                   jint length,
+                   const std::string& string)
+          : Elem(referrer, referree, size, length), string_(string) {}
+
+     protected:
+      std::string PrintArrowType() const OVERRIDE {
+        return string_;
+      }
+
+     private:
+      const std::string string_;
+    };
+
+    static std::unique_ptr<Elem> CreateElem(const std::string& referrer,
+                                            const std::string& referree,
+                                            jvmtiHeapReferenceKind reference_kind,
+                                            const jvmtiHeapReferenceInfo* reference_info,
+                                            jlong size,
+                                            jint length) {
+      switch (reference_kind) {
+        case JVMTI_HEAP_REFERENCE_CLASS:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "class"));
+        case JVMTI_HEAP_REFERENCE_FIELD: {
+          std::string tmp = StringPrintf("field@%d", reference_info->field.index);
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                        referree,
+                                                        size,
+                                                        length,
+                                                        tmp));
+        }
+        case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: {
+          std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         tmp));
+        }
+        case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "classloader"));
+        case JVMTI_HEAP_REFERENCE_SIGNERS:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "signers"));
+        case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "protection-domain"));
+        case JVMTI_HEAP_REFERENCE_INTERFACE:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "interface"));
+        case JVMTI_HEAP_REFERENCE_STATIC_FIELD: {
+          std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         tmp));;
+        }
+        case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "constant-pool"));
+        case JVMTI_HEAP_REFERENCE_SUPERCLASS:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "superclass"));
+        case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "jni-global"));
+        case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "system-class"));
+        case JVMTI_HEAP_REFERENCE_MONITOR:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "monitor"));
+        case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "stack-local"));
+        case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "jni-local"));
+        case JVMTI_HEAP_REFERENCE_THREAD:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "thread"));
+        case JVMTI_HEAP_REFERENCE_OTHER:
+          return std::unique_ptr<Elem>(new StringElement(referrer,
+                                                         referree,
+                                                         size,
+                                                         length,
+                                                         "other"));
+      }
+      LOG(FATAL) << "Unknown kind";
+      UNREACHABLE();
+    }
+
     static void DumpStacks() NO_THREAD_SAFETY_ANALYSIS {
       auto dump_function = [](art::Thread* t, void* data ATTRIBUTE_UNUSED) {
         std::string name;
@@ -209,58 +383,15 @@
       art::Runtime::Current()->GetThreadList()->ForEach(dump_function, nullptr);
     }
 
-    static std::string GetReferenceTypeStr(jvmtiHeapReferenceKind reference_kind,
-                                           const jvmtiHeapReferenceInfo* reference_info) {
-      switch (reference_kind) {
-        case JVMTI_HEAP_REFERENCE_CLASS:
-          return "class";
-        case JVMTI_HEAP_REFERENCE_FIELD:
-          return StringPrintf("field@%d", reference_info->field.index);
-        case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
-          return StringPrintf("array-element@%d", reference_info->array.index);
-        case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
-          return "classloader";
-        case JVMTI_HEAP_REFERENCE_SIGNERS:
-          return "signers";
-        case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
-          return "protection-domain";
-        case JVMTI_HEAP_REFERENCE_INTERFACE:
-          return "interface";
-        case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
-          return StringPrintf("static-field@%d", reference_info->field.index);
-        case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
-          return "constant-pool";
-        case JVMTI_HEAP_REFERENCE_SUPERCLASS:
-          return "superclass";
-        case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
-          return "jni-global";
-        case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
-          return "system-class";
-        case JVMTI_HEAP_REFERENCE_MONITOR:
-          return "monitor";
-        case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
-          return "stack-local";
-        case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
-          return "jni-local";
-        case JVMTI_HEAP_REFERENCE_THREAD:
-          return "thread";
-        case JVMTI_HEAP_REFERENCE_OTHER:
-          return "other";
-      }
-      return "unknown";
-    }
-
-    const std::vector<std::string>& GetLines() const {
-      return lines_;
-    }
-
-   private:
     jint counter_;
     const jint stop_after_;
     const jint follow_set_;
-    std::vector<std::string> lines_;
+
+    std::vector<std::unique_ptr<Elem>> lines_;
   };
 
+  jit::ScopedJitSuspend sjs;  // Wait to avoid JIT influence (e.g., JNI globals).
+
   // If jniRef isn't null, add a local and a global ref.
   ScopedLocalRef<jobject> jni_local_ref(env, nullptr);
   jobject jni_global_ref = nullptr;
@@ -272,7 +403,7 @@
   PrintIterationConfig config(stop_after, follow_set);
   Run(heap_filter, klass_filter, initial_object, &config);
 
-  const std::vector<std::string>& lines = config.GetLines();
+  std::vector<std::string> lines = config.GetLines();
   jobjectArray ret = CreateObjectArray(env,
                                        static_cast<jint>(lines.size()),
                                        "java/lang/String",
@@ -299,12 +430,5 @@
   return 0;
 }
 
-extern "C" JNIEXPORT void JNICALL Java_Main_waitForJitCompilation(JNIEnv*, jclass) {
-  jit::Jit* jit = Runtime::Current()->GetJit();
-  if (jit != nullptr) {
-    jit->WaitForCompilationToFinish(Thread::Current());
-  }
-}
-
 }  // namespace Test913Heaps
 }  // namespace art
diff --git a/test/913-heaps/src/Main.java b/test/913-heaps/src/Main.java
index fc00ada..a6ace9a 100644
--- a/test/913-heaps/src/Main.java
+++ b/test/913-heaps/src/Main.java
@@ -101,8 +101,6 @@
 
   private static void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
       Object asRoot, Verifier v, String additionalEnabled) {
-    waitForJitCompilation();  // Wait to avoid JIT influence (e.g., JNI globals).
-
     String[] lines =
         followReferences(0, null, root, stopAfter, followSet, asRoot);
 
@@ -388,6 +386,4 @@
 
   private static native String[] followReferences(int heapFilter, Class<?> klassFilter,
       Object initialObject, int stopAfter, int followSet, Object jniRef);
-
-  private static native void waitForJitCompilation();
 }
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index aab9f50..8713caa 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -25,10 +25,13 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.util.Arrays;
 
 public class Main {
 
   public static class A {
+    public A() {}
+
     public void foo() {
       System.out.println("foo_A");
     }
@@ -65,6 +68,7 @@
     testfindSpecial_invokeDirectBehaviour();
     testExceptionDetailMessages();
     testfindVirtual();
+    testfindStatic();
     testUnreflects();
     testAsType();
     testConstructors();
@@ -116,6 +120,19 @@
       System.out.println("findSpecial(A.class, foo, .. D.class) unexpectedly succeeded.");
     } catch (IllegalAccessException expected) {
     }
+
+    // Check return type matches for find.
+    try {
+      B.lookup.findSpecial(A.class /* refC */, "foo",
+                           MethodType.methodType(int.class), B.class /* specialCaller */);
+      fail();
+    } catch (NoSuchMethodException e) {}
+    // Check constructors
+    try {
+      B.lookup.findSpecial(A.class /* refC */, "<init>",
+                           MethodType.methodType(void.class), B.class /* specialCaller */);
+      fail();
+    } catch (NoSuchMethodException e) {}
   }
 
   public static void testfindSpecial_invokeDirectBehaviour() throws Throwable {
@@ -189,9 +206,20 @@
       return "bar";
     }
 
+    public String add(int x, int y) {
+      return Arrays.toString(new int[] { x, y });
+    }
+
     private String privateMethod() { return "privateMethod"; }
 
-    public static String staticMethod() { return null; }
+    public static String staticMethod() { return staticString; }
+
+    private static String staticString;
+
+    {
+      // Static constructor
+      staticString = Long.toString(System.currentTimeMillis());
+    }
 
     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
   }
@@ -232,6 +260,21 @@
       System.out.println("Unexpected return value for BarImpl#foo: " + str);
     }
 
+    // Find virtual should check rtype.
+    try {
+      mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo",
+                                              MethodType.methodType(void.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
+
+    // And ptypes
+    mh = MethodHandles.lookup().findVirtual(
+        BarImpl.class, "add", MethodType.methodType(String.class, int.class, int.class));
+    try {
+      mh = MethodHandles.lookup().findVirtual(
+          BarImpl.class, "add", MethodType.methodType(String.class, Integer.class, int.class));
+    } catch (NoSuchMethodException e) {}
+
     // .. and their super-interfaces.
     mh = MethodHandles.lookup().findVirtual(BarImpl.class, "bar",
         MethodType.methodType(String.class));
@@ -272,6 +315,37 @@
     if (!"superPackageMethod".equals(str)) {
       System.out.println("Unexpected return value for BarImpl#superPackageMethod: " + str);
     }
+
+    try {
+      MethodHandles.lookup().findVirtual(BarImpl.class, "<init>",
+                                        MethodType.methodType(void.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
+  }
+
+  public static void testfindStatic() throws Throwable {
+    MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
+                                      MethodType.methodType(String.class));
+    try {
+      MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
+                                        MethodType.methodType(void.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
+    try {
+      MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
+                                        MethodType.methodType(String.class, int.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
+    try {
+      MethodHandles.lookup().findStatic(BarImpl.class, "<clinit>",
+                                        MethodType.methodType(void.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
+    try {
+      MethodHandles.lookup().findStatic(BarImpl.class, "<init>",
+                                        MethodType.methodType(void.class));
+      fail();
+    } catch (NoSuchMethodException e) {}
   }
 
   static class UnreflectTester {
diff --git a/test/Android.arm_vixl.mk b/test/Android.arm_vixl.mk
index 845545c..21b31b4 100644
--- a/test/Android.arm_vixl.mk
+++ b/test/Android.arm_vixl.mk
@@ -17,56 +17,35 @@
 # Known broken tests for the ARM VIXL backend.
 TEST_ART_BROKEN_OPTIMIZING_ARM_VIXL_RUN_TESTS := \
   003-omnibus-opcodes \
-  004-ThreadStress \
-  028-array-write \
-  037-inherit \
+  020-string \
+  021-string2 \
   042-new-instance \
   044-proxy \
   080-oom-throw \
   082-inline-execute \
-  083-compiler-regressions \
   096-array-copy-concurrent-gc \
   099-vmdebug \
+  100-reflect2 \
   103-string-append \
   114-ParallelGC \
   122-npe \
-  123-inline-execute2 \
   129-ThreadGetId \
   137-cfi \
   144-static-field-sigquit \
-  201-built-in-except-detail-messages \
   412-new-array \
-  422-type-conversion \
-  437-inline \
   439-npe \
-  442-checker-constant-folding \
   450-checker-types \
-  458-checker-instruct-simplification \
-  458-long-to-fpu \
   488-checker-inline-recursive-calls \
-  510-checker-try-catch \
   515-dce-dominator \
   520-equivalent-phi \
   525-checker-arrays-fields1 \
   525-checker-arrays-fields2 \
   527-checker-array-access-split \
-  530-checker-loops2 \
-  530-checker-lse \
-  530-checker-lse2 \
-  535-regression-const-val \
-  536-checker-intrinsic-optimization \
   538-checker-embed-constants \
-  550-checker-multiply-accumulate \
-  552-checker-primitive-typeprop \
   552-checker-sharpening \
-  555-UnsafeGetLong-regression \
   562-checker-no-intermediate \
-  564-checker-negbitwise \
   570-checker-osr \
-  570-checker-select \
-  574-irreducible-and-constant-area \
-  580-checker-round \
-  594-checker-array-alias \
   602-deoptimizeable \
   700-LoadArgRegs \
   800-smali \
+
diff --git a/test/Android.bp b/test/Android.bp
index bdb7f80..fe20f29 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -266,10 +266,7 @@
 art_cc_test_library {
     name: "libtiagent",
     defaults: ["libtiagent-defaults"],
-    shared_libs: [
-        "libart",
-        "libopenjdkjvmti",
-    ],
+    shared_libs: ["libart"],
 }
 
 art_cc_test_library {
@@ -278,10 +275,7 @@
         "libtiagent-defaults",
         "art_debug_defaults",
     ],
-    shared_libs: [
-        "libartd",
-        "libopenjdkjvmtid",
-    ],
+    shared_libs: ["libartd"],
 }
 
 cc_defaults {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 60318a4..e92ba1a 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -804,7 +804,9 @@
   $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libnativebridgetest) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$(ART_HOST_SHLIB_EXTENSION) \
-  $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$(ART_HOST_SHLIB_EXTENSION)
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$(ART_HOST_SHLIB_EXTENSION) \
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmti$(ART_HOST_SHLIB_EXTENSION) \
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmtid$(ART_HOST_SHLIB_EXTENSION) \
 
 ifneq ($(HOST_PREFER_32_BIT),true)
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
@@ -817,7 +819,10 @@
   $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libnativebridgetest) \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$(ART_HOST_SHLIB_EXTENSION) \
-  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$(ART_HOST_SHLIB_EXTENSION)
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$(ART_HOST_SHLIB_EXTENSION) \
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmti$(ART_HOST_SHLIB_EXTENSION) \
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmtid$(ART_HOST_SHLIB_EXTENSION) \
+
 endif
 
 # Create a rule to build and run a tests following the form:
diff --git a/test/DexToDexDecompiler/Main.java b/test/DexToDexDecompiler/Main.java
new file mode 100644
index 0000000..8f5075a
--- /dev/null
+++ b/test/DexToDexDecompiler/Main.java
@@ -0,0 +1,34 @@
+/*
+ * 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 Main {
+  Main() {
+    // Will be quickened with RETURN_VOID_NO_BARRIER.
+  }
+
+  public static void main() {
+    Main m = new Main();
+    Object o = m;
+    // The call and field accesses will be quickened.
+    m.foo(m.a);
+
+    // The checkcast will be quickened.
+    m.foo(((Main)o).a);
+  }
+
+  int a;
+  void foo(int a) {}
+}
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 3cb1f23..c601e3e 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -139,8 +139,8 @@
         float f9, int i10, float f10);
 
     // Normal native
-    native static void stackArgsSignExtendedMips64(int i1, int i2, int i3, int i4, int i5, int i6,
-        int i7, int i8);
+    native static long getStackArgSignExtendedMips64(int i1, int i2, int i3, int i4, int i5, int i6,
+        int stack_arg);
 
     // Normal native
     static native double logD(double d);
@@ -273,8 +273,8 @@
         float f9, int i10, float f10);
 
     @FastNative
-    native static void stackArgsSignExtendedMips64_Fast(int i1, int i2, int i3, int i4, int i5, int i6,
-        int i7, int i8);
+    native static long getStackArgSignExtendedMips64_Fast(int i1, int i2, int i3, int i4, int i5, int i6,
+        int stack_arg);
 
     @FastNative
     static native double logD_Fast(double d);
@@ -316,10 +316,6 @@
         float f9, int i10, float f10);
 
     @CriticalNative
-    native static void stackArgsSignExtendedMips64_Critical(int i1, int i2, int i3, int i4, int i5, int i6,
-        int i7, int i8);
-
-    @CriticalNative
     static native double logD_Critical(double d);
     @CriticalNative
     static native float logF_Critical(float f);
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index c525b2b..06e4219 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -364,8 +364,8 @@
 if [ "$JIT" = "y" ]; then
     INT_OPTS="-Xusejit:true"
     if [ "$VERIFY" = "y" ] ; then
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-at-runtime"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=interpret-only"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
     else
       INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none"
       COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 12e0338..2d26b48 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -19,7 +19,17 @@
   exit 1
 fi
 
-out_dir=${OUT_DIR-out}
+# Logic for setting out_dir from build/make/core/envsetup.mk:
+if [[ -z $OUT_DIR ]]; then
+  if [[ -z $OUT_DIR_COMMON_BASE ]]; then
+    out_dir=out
+  else
+    out_dir=${OUT_DIR_COMMON_BASE}/${PWD##*/}
+  fi
+else
+  out_dir=${OUT_DIR}
+fi
+
 java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES
 common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target ${out_dir}/host/linux-x86/bin/jack"
 mode="target"