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"